@litfamily/litopencode 1.0.7 → 1.0.9

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 (723) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README-Ko-KR.md +314 -31
  3. package/README.md +312 -29
  4. package/dist/activation-primary-prompts.d.ts +1 -0
  5. package/dist/activation-primary-prompts.js +16 -0
  6. package/dist/activation-probe.js +4 -1
  7. package/dist/activation-prompt-utils.d.ts +1 -1
  8. package/dist/activation-routing.d.ts +6 -1
  9. package/dist/activation-routing.js +174 -16
  10. package/dist/activation-workflow-prompts.d.ts +1 -1
  11. package/dist/activation-workflow-prompts.js +18 -17
  12. package/dist/activation.d.ts +3 -2
  13. package/dist/activation.js +6 -6
  14. package/dist/agents/defaults.js +14 -6
  15. package/dist/cli/command-aliases.js +24 -22
  16. package/dist/cli/doctor.js +3 -0
  17. package/dist/cli/install-report.d.ts +1 -0
  18. package/dist/cli/install-report.js +4 -0
  19. package/dist/cli/install.js +7 -4
  20. package/dist/cli/managed-skill-assets.d.ts +1 -1
  21. package/dist/cli/managed-skill-assets.js +15 -5
  22. package/dist/cli/motion-runtime.d.ts +6 -0
  23. package/dist/cli/motion-runtime.js +46 -0
  24. package/dist/cli/native-skill-install.js +32 -9
  25. package/dist/cli/native-skill-integrity.js +1 -0
  26. package/dist/cli/native-skills.d.ts +2 -0
  27. package/dist/cli/native-skills.js +2 -1
  28. package/dist/cli/office-dependencies.d.ts +14 -0
  29. package/dist/cli/office-dependencies.js +24 -0
  30. package/dist/cli.js +13 -3
  31. package/dist/commands.d.ts +2 -11
  32. package/dist/commands.js +9 -17
  33. package/dist/deliverable-hedge-guard.d.ts +20 -21
  34. package/dist/deliverable-hedge-guard.js +234 -275
  35. package/dist/features.d.ts +81 -2
  36. package/dist/features.js +80 -13
  37. package/dist/hooks.d.ts +3 -2
  38. package/dist/hooks.js +4 -4
  39. package/dist/ignition.d.ts +1 -1
  40. package/dist/ignition.js +15 -4
  41. package/dist/index.d.ts +1 -1
  42. package/dist/index.js +1 -1
  43. package/dist/interface-handoff.d.ts +1 -0
  44. package/dist/interface-handoff.js +1 -0
  45. package/dist/motion-image-reads.d.ts +6 -0
  46. package/dist/motion-image-reads.js +46 -0
  47. package/dist/server.js +13 -11
  48. package/dist/skill-renames.d.ts +4 -2
  49. package/dist/skill-renames.js +12 -4
  50. package/dist/skills.d.ts +31 -3
  51. package/dist/skills.js +53 -9
  52. package/dist/tools.js +4 -4
  53. package/docs/ab/S11/baseline-desktop.webp +0 -0
  54. package/docs/ab/S11/baseline-phone.webp +0 -0
  55. package/docs/ab/S11/lit-desktop.webp +0 -0
  56. package/docs/ab/S11/lit-phone.webp +0 -0
  57. package/docs/ab/S3/baseline-desktop.webp +0 -0
  58. package/docs/ab/S3/baseline-phone.webp +0 -0
  59. package/docs/ab/S3/lit-desktop.webp +0 -0
  60. package/docs/ab/S3/lit-phone.webp +0 -0
  61. package/docs/ab/S4/baseline-desktop.webp +0 -0
  62. package/docs/ab/S4/baseline-phone.webp +0 -0
  63. package/docs/ab/S4/lit-desktop.webp +0 -0
  64. package/docs/ab/S4/lit-phone.webp +0 -0
  65. package/docs/ab/S5/lit-slides.webp +0 -0
  66. package/docs/ab/S7/lit-diagram.webp +0 -0
  67. package/docs/ab/S8/baseline-slides.webp +0 -0
  68. package/docs/ab/S8/lit-slides.webp +0 -0
  69. package/docs/ab/S9/lit-pages.webp +0 -0
  70. package/docs/assets/cover-motion-still.webp +0 -0
  71. package/docs/assets/cover-motion.webp +0 -0
  72. package/docs/assets/readme/badge-version.svg +1 -1
  73. package/docs/assets/skills/autoconference.webp +0 -0
  74. package/docs/assets/skills/automatic-guards.webp +0 -0
  75. package/docs/assets/skills/autoresearch.webp +0 -0
  76. package/docs/assets/skills/browser-drive.webp +0 -0
  77. package/docs/assets/skills/debugging.webp +0 -0
  78. package/docs/assets/skills/deep-interview.webp +0 -0
  79. package/docs/assets/skills/doctor-installer.webp +0 -0
  80. package/docs/assets/skills/durable-litgoal.webp +0 -0
  81. package/docs/assets/skills/frontend-ui-ux.webp +0 -0
  82. package/docs/assets/skills/lit-burnoff-file.webp +0 -0
  83. package/docs/assets/skills/lit-burnoff.webp +0 -0
  84. package/docs/assets/skills/lit-code.webp +0 -0
  85. package/docs/assets/skills/lit-commit.webp +0 -0
  86. package/docs/assets/skills/lit-comprehend.webp +0 -0
  87. package/docs/assets/skills/lit-crucible.webp +0 -0
  88. package/docs/assets/skills/lit-diagram-drawer.webp +0 -0
  89. package/docs/assets/skills/lit-docx.webp +0 -0
  90. package/docs/assets/skills/lit-fetch.webp +0 -0
  91. package/docs/assets/skills/lit-handoff.webp +0 -0
  92. package/docs/assets/skills/lit-humanizer.webp +0 -0
  93. package/docs/assets/skills/lit-init.webp +0 -0
  94. package/docs/assets/skills/lit-plan.webp +0 -0
  95. package/docs/assets/skills/lit-pptx.webp +0 -0
  96. package/docs/assets/skills/lit-recap.webp +0 -0
  97. package/docs/assets/skills/lit-scientific-visualization.webp +0 -0
  98. package/docs/assets/skills/lit-typographic-motion.webp +0 -0
  99. package/docs/assets/skills/litresearch.webp +0 -0
  100. package/docs/assets/skills/litwork.webp +0 -0
  101. package/docs/assets/skills/lsp-setup.webp +0 -0
  102. package/docs/assets/skills/lsp.webp +0 -0
  103. package/docs/assets/skills/readme-studio.webp +0 -0
  104. package/docs/assets/skills/refactor.webp +0 -0
  105. package/docs/assets/skills/review-work.webp +0 -0
  106. package/docs/assets/skills/rules.webp +0 -0
  107. package/docs/assets/skills/start-work.webp +0 -0
  108. package/docs/assets/skills/structural-search.webp +0 -0
  109. package/docs/assets/skills/visual-qa.webp +0 -0
  110. package/docs/assets/skills/wikify.webp +0 -0
  111. package/docs/reference-Ko-KR.md +5 -1
  112. package/docs/reference.md +6 -2
  113. package/package.json +1 -1
  114. package/rules/bundled-rules/lit-humanizer.md +12 -0
  115. package/skills/autoconference/SKILL.md +1 -1
  116. package/skills/autoconference/assets/report_template.md +1 -1
  117. package/skills/autoresearch/references/type-checklists.md +1 -1
  118. package/skills/browser-drive/SKILL.md +19 -5
  119. package/skills/browser-drive/scripts/capability-probe.mjs +26 -5
  120. package/skills/frontend-ui-ux/SKILL.md +10 -15
  121. package/skills/frontend-ui-ux/data/THIRD-PARTY-NOTICE.txt +10 -0
  122. package/skills/frontend-ui-ux/references/adaptive-layout.md +3 -11
  123. package/skills/frontend-ui-ux/references/brand-and-imagery.md +6 -11
  124. package/skills/frontend-ui-ux/references/complete-contract.md +10 -3
  125. package/skills/frontend-ui-ux/references/composition.md +1 -7
  126. package/skills/frontend-ui-ux/references/craft-floor.md +94 -0
  127. package/skills/frontend-ui-ux/references/creative-directions.md +1 -7
  128. package/skills/frontend-ui-ux/references/evidence-review.md +2 -12
  129. package/skills/frontend-ui-ux/references/implementation-platforms.md +1 -4
  130. package/skills/frontend-ui-ux/references/inclusive-interface.md +1 -3
  131. package/skills/frontend-ui-ux/references/interaction-motion.md +1 -7
  132. package/skills/frontend-ui-ux/references/motion-guide.md +125 -0
  133. package/skills/frontend-ui-ux/references/operating-lanes.md +2 -8
  134. package/skills/frontend-ui-ux/references/product-direction.md +1 -6
  135. package/skills/frontend-ui-ux/references/production.md +12 -5
  136. package/skills/frontend-ui-ux/references/redesign-playbook.md +1 -7
  137. package/skills/frontend-ui-ux/references/slop-register.md +103 -0
  138. package/skills/frontend-ui-ux/references/system-foundations.md +1 -8
  139. package/skills/frontend-ui-ux/references/taste-direction.md +4 -11
  140. package/skills/frontend-ui-ux/references/visual-language.md +1 -6
  141. package/skills/frontend-ui-ux/references/visual-reconstruction.md +2 -7
  142. package/skills/frontend-ui-ux/scripts/probe-page.mjs +326 -0
  143. package/skills/frontend-ui-ux/scripts/probe-server.mjs +24 -0
  144. package/skills/frontend-ui-ux/scripts/probe-static.mjs +42 -0
  145. package/skills/frontend-ui-ux/scripts/probe-thresholds.json +86 -0
  146. package/skills/frontend-ui-ux/scripts/probe.mjs +183 -0
  147. package/skills/lit-comprehend/SKILL.md +10 -11
  148. package/skills/lit-comprehend/references/artifact-template.md +2 -18
  149. package/skills/lit-comprehend/scripts/verify-explainer.ts +0 -14
  150. package/skills/lit-diagram-drawer/NOTICE.md +33 -0
  151. package/skills/lit-diagram-drawer/SKILL.md +101 -0
  152. package/skills/lit-diagram-drawer/assets/examples/type-architecture-dark.html +1 -0
  153. package/skills/lit-diagram-drawer/assets/examples/type-architecture-full.html +1 -0
  154. package/skills/lit-diagram-drawer/assets/examples/type-architecture-light.html +1 -0
  155. package/skills/lit-diagram-drawer/assets/examples/type-bar-dark.html +1 -0
  156. package/skills/lit-diagram-drawer/assets/examples/type-bar-full.html +1 -0
  157. package/skills/lit-diagram-drawer/assets/examples/type-bar-light.html +1 -0
  158. package/skills/lit-diagram-drawer/assets/examples/type-beeswarm-dark.html +1 -0
  159. package/skills/lit-diagram-drawer/assets/examples/type-beeswarm-full.html +1 -0
  160. package/skills/lit-diagram-drawer/assets/examples/type-beeswarm-light.html +1 -0
  161. package/skills/lit-diagram-drawer/assets/examples/type-bubble-dark.html +1 -0
  162. package/skills/lit-diagram-drawer/assets/examples/type-bubble-full.html +1 -0
  163. package/skills/lit-diagram-drawer/assets/examples/type-bubble-light.html +1 -0
  164. package/skills/lit-diagram-drawer/assets/examples/type-bump-dark.html +1 -0
  165. package/skills/lit-diagram-drawer/assets/examples/type-bump-full.html +1 -0
  166. package/skills/lit-diagram-drawer/assets/examples/type-bump-light.html +1 -0
  167. package/skills/lit-diagram-drawer/assets/examples/type-data-flow-dark.html +1 -0
  168. package/skills/lit-diagram-drawer/assets/examples/type-data-flow-full.html +1 -0
  169. package/skills/lit-diagram-drawer/assets/examples/type-data-flow-light.html +1 -0
  170. package/skills/lit-diagram-drawer/assets/examples/type-datalake-dark.html +1 -0
  171. package/skills/lit-diagram-drawer/assets/examples/type-datalake-full.html +1 -0
  172. package/skills/lit-diagram-drawer/assets/examples/type-datalake-light.html +1 -0
  173. package/skills/lit-diagram-drawer/assets/examples/type-db-schema-dark.html +1 -0
  174. package/skills/lit-diagram-drawer/assets/examples/type-db-schema-full.html +1 -0
  175. package/skills/lit-diagram-drawer/assets/examples/type-db-schema-light.html +1 -0
  176. package/skills/lit-diagram-drawer/assets/examples/type-dependency-dark.html +1 -0
  177. package/skills/lit-diagram-drawer/assets/examples/type-dependency-full.html +1 -0
  178. package/skills/lit-diagram-drawer/assets/examples/type-dependency-light.html +1 -0
  179. package/skills/lit-diagram-drawer/assets/examples/type-deployment-dark.html +1 -0
  180. package/skills/lit-diagram-drawer/assets/examples/type-deployment-full.html +1 -0
  181. package/skills/lit-diagram-drawer/assets/examples/type-deployment-light.html +1 -0
  182. package/skills/lit-diagram-drawer/assets/examples/type-dp-integration-dark.html +1 -0
  183. package/skills/lit-diagram-drawer/assets/examples/type-dp-integration-full.html +1 -0
  184. package/skills/lit-diagram-drawer/assets/examples/type-dp-integration-light.html +1 -0
  185. package/skills/lit-diagram-drawer/assets/examples/type-dp-security-matrix-dark.html +1 -0
  186. package/skills/lit-diagram-drawer/assets/examples/type-dp-security-matrix-full.html +1 -0
  187. package/skills/lit-diagram-drawer/assets/examples/type-dp-security-matrix-light.html +1 -0
  188. package/skills/lit-diagram-drawer/assets/examples/type-er-dark.html +1 -0
  189. package/skills/lit-diagram-drawer/assets/examples/type-er-full.html +1 -0
  190. package/skills/lit-diagram-drawer/assets/examples/type-er-light.html +1 -0
  191. package/skills/lit-diagram-drawer/assets/examples/type-fishbone-dark.html +1 -0
  192. package/skills/lit-diagram-drawer/assets/examples/type-fishbone-full.html +1 -0
  193. package/skills/lit-diagram-drawer/assets/examples/type-fishbone-light.html +1 -0
  194. package/skills/lit-diagram-drawer/assets/examples/type-flowchart-dark.html +1 -0
  195. package/skills/lit-diagram-drawer/assets/examples/type-flowchart-full.html +1 -0
  196. package/skills/lit-diagram-drawer/assets/examples/type-flowchart-light.html +1 -0
  197. package/skills/lit-diagram-drawer/assets/examples/type-gantt-dark.html +1 -0
  198. package/skills/lit-diagram-drawer/assets/examples/type-gantt-full.html +1 -0
  199. package/skills/lit-diagram-drawer/assets/examples/type-gantt-light.html +1 -0
  200. package/skills/lit-diagram-drawer/assets/examples/type-heatmap-dark.html +1 -0
  201. package/skills/lit-diagram-drawer/assets/examples/type-heatmap-full.html +1 -0
  202. package/skills/lit-diagram-drawer/assets/examples/type-heatmap-light.html +1 -0
  203. package/skills/lit-diagram-drawer/assets/examples/type-high-level-dark.html +1 -0
  204. package/skills/lit-diagram-drawer/assets/examples/type-high-level-full.html +1 -0
  205. package/skills/lit-diagram-drawer/assets/examples/type-high-level-light.html +1 -0
  206. package/skills/lit-diagram-drawer/assets/examples/type-high-level-vertical-dark.html +1 -0
  207. package/skills/lit-diagram-drawer/assets/examples/type-high-level-vertical-full.html +1 -0
  208. package/skills/lit-diagram-drawer/assets/examples/type-high-level-vertical-light.html +1 -0
  209. package/skills/lit-diagram-drawer/assets/examples/type-import-drawio-dark.html +1 -0
  210. package/skills/lit-diagram-drawer/assets/examples/type-import-drawio-full.html +1 -0
  211. package/skills/lit-diagram-drawer/assets/examples/type-import-drawio-light.html +1 -0
  212. package/skills/lit-diagram-drawer/assets/examples/type-import-excalidraw-dark.html +1 -0
  213. package/skills/lit-diagram-drawer/assets/examples/type-import-excalidraw-full.html +1 -0
  214. package/skills/lit-diagram-drawer/assets/examples/type-import-excalidraw-light.html +1 -0
  215. package/skills/lit-diagram-drawer/assets/examples/type-import-mermaid-dark.html +1 -0
  216. package/skills/lit-diagram-drawer/assets/examples/type-import-mermaid-full.html +1 -0
  217. package/skills/lit-diagram-drawer/assets/examples/type-import-mermaid-light.html +1 -0
  218. package/skills/lit-diagram-drawer/assets/examples/type-it-state-dark.html +1 -0
  219. package/skills/lit-diagram-drawer/assets/examples/type-it-state-full.html +1 -0
  220. package/skills/lit-diagram-drawer/assets/examples/type-it-state-light.html +1 -0
  221. package/skills/lit-diagram-drawer/assets/examples/type-journey-dark.html +1 -0
  222. package/skills/lit-diagram-drawer/assets/examples/type-journey-full.html +1 -0
  223. package/skills/lit-diagram-drawer/assets/examples/type-journey-light.html +1 -0
  224. package/skills/lit-diagram-drawer/assets/examples/type-kanban-dark.html +1 -0
  225. package/skills/lit-diagram-drawer/assets/examples/type-kanban-full.html +1 -0
  226. package/skills/lit-diagram-drawer/assets/examples/type-kanban-light.html +1 -0
  227. package/skills/lit-diagram-drawer/assets/examples/type-layers-dark.html +1 -0
  228. package/skills/lit-diagram-drawer/assets/examples/type-layers-full.html +1 -0
  229. package/skills/lit-diagram-drawer/assets/examples/type-layers-light.html +1 -0
  230. package/skills/lit-diagram-drawer/assets/examples/type-line-dark.html +1 -0
  231. package/skills/lit-diagram-drawer/assets/examples/type-line-full.html +1 -0
  232. package/skills/lit-diagram-drawer/assets/examples/type-line-light.html +1 -0
  233. package/skills/lit-diagram-drawer/assets/examples/type-loop-dark.html +1 -0
  234. package/skills/lit-diagram-drawer/assets/examples/type-loop-full.html +1 -0
  235. package/skills/lit-diagram-drawer/assets/examples/type-loop-light.html +1 -0
  236. package/skills/lit-diagram-drawer/assets/examples/type-loop-terminal-dark.html +1 -0
  237. package/skills/lit-diagram-drawer/assets/examples/type-loop-terminal-full.html +1 -0
  238. package/skills/lit-diagram-drawer/assets/examples/type-loop-terminal-light.html +1 -0
  239. package/skills/lit-diagram-drawer/assets/examples/type-marimekko-dark.html +1 -0
  240. package/skills/lit-diagram-drawer/assets/examples/type-marimekko-full.html +1 -0
  241. package/skills/lit-diagram-drawer/assets/examples/type-marimekko-light.html +1 -0
  242. package/skills/lit-diagram-drawer/assets/examples/type-medallion-dark.html +1 -0
  243. package/skills/lit-diagram-drawer/assets/examples/type-medallion-full.html +1 -0
  244. package/skills/lit-diagram-drawer/assets/examples/type-medallion-light.html +1 -0
  245. package/skills/lit-diagram-drawer/assets/examples/type-nested-dark.html +1 -0
  246. package/skills/lit-diagram-drawer/assets/examples/type-nested-full.html +1 -0
  247. package/skills/lit-diagram-drawer/assets/examples/type-nested-light.html +1 -0
  248. package/skills/lit-diagram-drawer/assets/examples/type-org-chart-dark.html +1 -0
  249. package/skills/lit-diagram-drawer/assets/examples/type-org-chart-full.html +1 -0
  250. package/skills/lit-diagram-drawer/assets/examples/type-org-chart-light.html +1 -0
  251. package/skills/lit-diagram-drawer/assets/examples/type-paved-road-animated-dark.html +1 -0
  252. package/skills/lit-diagram-drawer/assets/examples/type-paved-road-animated-full.html +1 -0
  253. package/skills/lit-diagram-drawer/assets/examples/type-paved-road-animated-light.html +1 -0
  254. package/skills/lit-diagram-drawer/assets/examples/type-polar-dark.html +1 -0
  255. package/skills/lit-diagram-drawer/assets/examples/type-polar-full.html +1 -0
  256. package/skills/lit-diagram-drawer/assets/examples/type-polar-light.html +1 -0
  257. package/skills/lit-diagram-drawer/assets/examples/type-policy-trace-animated-dark.html +1 -0
  258. package/skills/lit-diagram-drawer/assets/examples/type-policy-trace-animated-full.html +1 -0
  259. package/skills/lit-diagram-drawer/assets/examples/type-policy-trace-animated-light.html +1 -0
  260. package/skills/lit-diagram-drawer/assets/examples/type-process-dark.html +1 -0
  261. package/skills/lit-diagram-drawer/assets/examples/type-process-full.html +1 -0
  262. package/skills/lit-diagram-drawer/assets/examples/type-process-light.html +1 -0
  263. package/skills/lit-diagram-drawer/assets/examples/type-pyramid-dark.html +1 -0
  264. package/skills/lit-diagram-drawer/assets/examples/type-pyramid-full.html +1 -0
  265. package/skills/lit-diagram-drawer/assets/examples/type-pyramid-light.html +1 -0
  266. package/skills/lit-diagram-drawer/assets/examples/type-quadrant-consultant-dark.html +1 -0
  267. package/skills/lit-diagram-drawer/assets/examples/type-quadrant-consultant-full.html +1 -0
  268. package/skills/lit-diagram-drawer/assets/examples/type-quadrant-consultant-light.html +1 -0
  269. package/skills/lit-diagram-drawer/assets/examples/type-quadrant-dark.html +1 -0
  270. package/skills/lit-diagram-drawer/assets/examples/type-quadrant-full.html +1 -0
  271. package/skills/lit-diagram-drawer/assets/examples/type-quadrant-light.html +1 -0
  272. package/skills/lit-diagram-drawer/assets/examples/type-queue-animated-dark.html +1 -0
  273. package/skills/lit-diagram-drawer/assets/examples/type-queue-animated-full.html +1 -0
  274. package/skills/lit-diagram-drawer/assets/examples/type-queue-animated-light.html +1 -0
  275. package/skills/lit-diagram-drawer/assets/examples/type-radar-dark.html +1 -0
  276. package/skills/lit-diagram-drawer/assets/examples/type-radar-full.html +1 -0
  277. package/skills/lit-diagram-drawer/assets/examples/type-radar-light.html +1 -0
  278. package/skills/lit-diagram-drawer/assets/examples/type-ridgeline-dark.html +1 -0
  279. package/skills/lit-diagram-drawer/assets/examples/type-ridgeline-full.html +1 -0
  280. package/skills/lit-diagram-drawer/assets/examples/type-ridgeline-light.html +1 -0
  281. package/skills/lit-diagram-drawer/assets/examples/type-sankey-dark.html +1 -0
  282. package/skills/lit-diagram-drawer/assets/examples/type-sankey-full.html +1 -0
  283. package/skills/lit-diagram-drawer/assets/examples/type-sankey-light.html +1 -0
  284. package/skills/lit-diagram-drawer/assets/examples/type-scatter-dark.html +1 -0
  285. package/skills/lit-diagram-drawer/assets/examples/type-scatter-full.html +1 -0
  286. package/skills/lit-diagram-drawer/assets/examples/type-scatter-light.html +1 -0
  287. package/skills/lit-diagram-drawer/assets/examples/type-sequence-dark.html +1 -0
  288. package/skills/lit-diagram-drawer/assets/examples/type-sequence-full.html +1 -0
  289. package/skills/lit-diagram-drawer/assets/examples/type-sequence-light.html +1 -0
  290. package/skills/lit-diagram-drawer/assets/examples/type-sequence-oauth-dark.html +1 -0
  291. package/skills/lit-diagram-drawer/assets/examples/type-sequence-oauth-full.html +1 -0
  292. package/skills/lit-diagram-drawer/assets/examples/type-sequence-oauth-light.html +1 -0
  293. package/skills/lit-diagram-drawer/assets/examples/type-slopegraph-dark.html +1 -0
  294. package/skills/lit-diagram-drawer/assets/examples/type-slopegraph-full.html +1 -0
  295. package/skills/lit-diagram-drawer/assets/examples/type-slopegraph-light.html +1 -0
  296. package/skills/lit-diagram-drawer/assets/examples/type-state-dark.html +1 -0
  297. package/skills/lit-diagram-drawer/assets/examples/type-state-full.html +1 -0
  298. package/skills/lit-diagram-drawer/assets/examples/type-state-lifecycle-dark.html +1 -0
  299. package/skills/lit-diagram-drawer/assets/examples/type-state-lifecycle-full.html +1 -0
  300. package/skills/lit-diagram-drawer/assets/examples/type-state-lifecycle-light.html +1 -0
  301. package/skills/lit-diagram-drawer/assets/examples/type-state-light.html +1 -0
  302. package/skills/lit-diagram-drawer/assets/examples/type-story-map-dark.html +1 -0
  303. package/skills/lit-diagram-drawer/assets/examples/type-story-map-full.html +1 -0
  304. package/skills/lit-diagram-drawer/assets/examples/type-story-map-light.html +1 -0
  305. package/skills/lit-diagram-drawer/assets/examples/type-streamgraph-dark.html +1 -0
  306. package/skills/lit-diagram-drawer/assets/examples/type-streamgraph-full.html +1 -0
  307. package/skills/lit-diagram-drawer/assets/examples/type-streamgraph-light.html +1 -0
  308. package/skills/lit-diagram-drawer/assets/examples/type-swimlane-dark.html +1 -0
  309. package/skills/lit-diagram-drawer/assets/examples/type-swimlane-full.html +1 -0
  310. package/skills/lit-diagram-drawer/assets/examples/type-swimlane-light.html +1 -0
  311. package/skills/lit-diagram-drawer/assets/examples/type-timeline-dark.html +1 -0
  312. package/skills/lit-diagram-drawer/assets/examples/type-timeline-full.html +1 -0
  313. package/skills/lit-diagram-drawer/assets/examples/type-timeline-light.html +1 -0
  314. package/skills/lit-diagram-drawer/assets/examples/type-tree-block-decomposition-dark.html +1 -0
  315. package/skills/lit-diagram-drawer/assets/examples/type-tree-block-decomposition-full.html +1 -0
  316. package/skills/lit-diagram-drawer/assets/examples/type-tree-block-decomposition-light.html +1 -0
  317. package/skills/lit-diagram-drawer/assets/examples/type-tree-dark.html +1 -0
  318. package/skills/lit-diagram-drawer/assets/examples/type-tree-full.html +1 -0
  319. package/skills/lit-diagram-drawer/assets/examples/type-tree-light.html +1 -0
  320. package/skills/lit-diagram-drawer/assets/examples/type-treemap-dark.html +1 -0
  321. package/skills/lit-diagram-drawer/assets/examples/type-treemap-full.html +1 -0
  322. package/skills/lit-diagram-drawer/assets/examples/type-treemap-light.html +1 -0
  323. package/skills/lit-diagram-drawer/assets/examples/type-uml-class-dark.html +1 -0
  324. package/skills/lit-diagram-drawer/assets/examples/type-uml-class-full.html +1 -0
  325. package/skills/lit-diagram-drawer/assets/examples/type-uml-class-light.html +1 -0
  326. package/skills/lit-diagram-drawer/assets/examples/type-venn-dark.html +1 -0
  327. package/skills/lit-diagram-drawer/assets/examples/type-venn-full.html +1 -0
  328. package/skills/lit-diagram-drawer/assets/examples/type-venn-light.html +1 -0
  329. package/skills/lit-diagram-drawer/assets/examples/type-wardley-dark.html +1 -0
  330. package/skills/lit-diagram-drawer/assets/examples/type-wardley-full.html +1 -0
  331. package/skills/lit-diagram-drawer/assets/examples/type-wardley-light.html +1 -0
  332. package/skills/lit-diagram-drawer/assets/examples/type-waterfall-dark.html +1 -0
  333. package/skills/lit-diagram-drawer/assets/examples/type-waterfall-full.html +1 -0
  334. package/skills/lit-diagram-drawer/assets/examples/type-waterfall-light.html +1 -0
  335. package/skills/lit-diagram-drawer/assets/fonts/OFL.txt +94 -0
  336. package/skills/lit-diagram-drawer/assets/fonts/PretendardVariable.woff2 +0 -0
  337. package/skills/lit-diagram-drawer/assets/fonts/provenance.json +23 -0
  338. package/skills/lit-diagram-drawer/assets/icons.html +231 -0
  339. package/skills/lit-diagram-drawer/assets/licenses/devicon-MIT.txt +20 -0
  340. package/skills/lit-diagram-drawer/assets/licenses/diagram-design-MIT.txt +21 -0
  341. package/skills/lit-diagram-drawer/assets/licenses/log-z-MIT.txt +21 -0
  342. package/skills/lit-diagram-drawer/assets/licenses/simple-icons-CC0.md +30 -0
  343. package/skills/lit-diagram-drawer/assets/licenses/tabler-MIT.txt +21 -0
  344. package/skills/lit-diagram-drawer/examples/01-service-architecture/after.html +1 -0
  345. package/skills/lit-diagram-drawer/examples/01-service-architecture/brief.md +33 -0
  346. package/skills/lit-diagram-drawer/examples/02-release-decision/after.html +1 -0
  347. package/skills/lit-diagram-drawer/examples/02-release-decision/brief.md +18 -0
  348. package/skills/lit-diagram-drawer/examples/03-data-retention/after.html +1 -0
  349. package/skills/lit-diagram-drawer/examples/03-data-retention/brief.md +19 -0
  350. package/skills/lit-diagram-drawer/examples/04-oauth-sequence/after.html +1 -0
  351. package/skills/lit-diagram-drawer/examples/04-oauth-sequence/brief.md +17 -0
  352. package/skills/lit-diagram-drawer/examples/05-review-lanes/after.html +1 -0
  353. package/skills/lit-diagram-drawer/examples/05-review-lanes/brief.md +17 -0
  354. package/skills/lit-diagram-drawer/examples/06-rollout-gates/after.html +1 -0
  355. package/skills/lit-diagram-drawer/examples/06-rollout-gates/brief.md +17 -0
  356. package/skills/lit-diagram-drawer/examples/07-deployment-boundary/after.html +1 -0
  357. package/skills/lit-diagram-drawer/examples/07-deployment-boundary/brief.md +19 -0
  358. package/skills/lit-diagram-drawer/examples/08-policy-traces/after.html +1 -0
  359. package/skills/lit-diagram-drawer/examples/08-policy-traces/brief.md +20 -0
  360. package/skills/lit-diagram-drawer/references/accessibility.md +37 -0
  361. package/skills/lit-diagram-drawer/references/export.md +17 -0
  362. package/skills/lit-diagram-drawer/references/import-drawio.md +13 -0
  363. package/skills/lit-diagram-drawer/references/import-excalidraw.md +11 -0
  364. package/skills/lit-diagram-drawer/references/import-mermaid.md +12 -0
  365. package/skills/lit-diagram-drawer/references/import-schema.md +28 -0
  366. package/skills/lit-diagram-drawer/references/korean-typography.md +34 -0
  367. package/skills/lit-diagram-drawer/references/motion.md +29 -0
  368. package/skills/lit-diagram-drawer/references/office-pptx-docx.md +28 -0
  369. package/skills/lit-diagram-drawer/references/output-spec.md +48 -0
  370. package/skills/lit-diagram-drawer/references/primitive-annotation.md +12 -0
  371. package/skills/lit-diagram-drawer/references/primitive-icons.md +21 -0
  372. package/skills/lit-diagram-drawer/references/primitive-sketchy.md +11 -0
  373. package/skills/lit-diagram-drawer/references/primitive-terminal.md +11 -0
  374. package/skills/lit-diagram-drawer/references/profiles.md +24 -0
  375. package/skills/lit-diagram-drawer/references/semantic-patterns.md +27 -0
  376. package/skills/lit-diagram-drawer/references/style-guide.md +67 -0
  377. package/skills/lit-diagram-drawer/references/type-architecture.md +51 -0
  378. package/skills/lit-diagram-drawer/references/type-bar.md +51 -0
  379. package/skills/lit-diagram-drawer/references/type-beeswarm.md +49 -0
  380. package/skills/lit-diagram-drawer/references/type-bubble.md +49 -0
  381. package/skills/lit-diagram-drawer/references/type-bump.md +49 -0
  382. package/skills/lit-diagram-drawer/references/type-catalog.json +1433 -0
  383. package/skills/lit-diagram-drawer/references/type-data-flow.md +51 -0
  384. package/skills/lit-diagram-drawer/references/type-datalake.md +49 -0
  385. package/skills/lit-diagram-drawer/references/type-db-schema.md +49 -0
  386. package/skills/lit-diagram-drawer/references/type-dependency.md +49 -0
  387. package/skills/lit-diagram-drawer/references/type-deployment.md +49 -0
  388. package/skills/lit-diagram-drawer/references/type-dp-integration.md +49 -0
  389. package/skills/lit-diagram-drawer/references/type-dp-security-matrix.md +49 -0
  390. package/skills/lit-diagram-drawer/references/type-er.md +49 -0
  391. package/skills/lit-diagram-drawer/references/type-fishbone.md +49 -0
  392. package/skills/lit-diagram-drawer/references/type-flowchart.md +49 -0
  393. package/skills/lit-diagram-drawer/references/type-gantt.md +49 -0
  394. package/skills/lit-diagram-drawer/references/type-heatmap.md +53 -0
  395. package/skills/lit-diagram-drawer/references/type-high-level-vertical.md +53 -0
  396. package/skills/lit-diagram-drawer/references/type-high-level.md +53 -0
  397. package/skills/lit-diagram-drawer/references/type-import-drawio.md +53 -0
  398. package/skills/lit-diagram-drawer/references/type-import-excalidraw.md +53 -0
  399. package/skills/lit-diagram-drawer/references/type-import-mermaid.md +53 -0
  400. package/skills/lit-diagram-drawer/references/type-it-state.md +54 -0
  401. package/skills/lit-diagram-drawer/references/type-journey.md +54 -0
  402. package/skills/lit-diagram-drawer/references/type-kanban.md +54 -0
  403. package/skills/lit-diagram-drawer/references/type-layers.md +54 -0
  404. package/skills/lit-diagram-drawer/references/type-line.md +54 -0
  405. package/skills/lit-diagram-drawer/references/type-loop-terminal.md +53 -0
  406. package/skills/lit-diagram-drawer/references/type-loop.md +54 -0
  407. package/skills/lit-diagram-drawer/references/type-marimekko.md +54 -0
  408. package/skills/lit-diagram-drawer/references/type-medallion.md +54 -0
  409. package/skills/lit-diagram-drawer/references/type-nested.md +59 -0
  410. package/skills/lit-diagram-drawer/references/type-org-chart.md +58 -0
  411. package/skills/lit-diagram-drawer/references/type-paved-road-animated.md +72 -0
  412. package/skills/lit-diagram-drawer/references/type-polar.md +67 -0
  413. package/skills/lit-diagram-drawer/references/type-policy-trace-animated.md +69 -0
  414. package/skills/lit-diagram-drawer/references/type-process.md +58 -0
  415. package/skills/lit-diagram-drawer/references/type-pyramid.md +59 -0
  416. package/skills/lit-diagram-drawer/references/type-quadrant-consultant.md +60 -0
  417. package/skills/lit-diagram-drawer/references/type-quadrant.md +57 -0
  418. package/skills/lit-diagram-drawer/references/type-queue-animated.md +63 -0
  419. package/skills/lit-diagram-drawer/references/type-radar.md +57 -0
  420. package/skills/lit-diagram-drawer/references/type-ridgeline.md +63 -0
  421. package/skills/lit-diagram-drawer/references/type-sankey.md +68 -0
  422. package/skills/lit-diagram-drawer/references/type-scatter.md +60 -0
  423. package/skills/lit-diagram-drawer/references/type-sequence-oauth.md +66 -0
  424. package/skills/lit-diagram-drawer/references/type-sequence.md +63 -0
  425. package/skills/lit-diagram-drawer/references/type-slopegraph.md +65 -0
  426. package/skills/lit-diagram-drawer/references/type-state-lifecycle.md +53 -0
  427. package/skills/lit-diagram-drawer/references/type-state.md +59 -0
  428. package/skills/lit-diagram-drawer/references/type-story-map.md +52 -0
  429. package/skills/lit-diagram-drawer/references/type-streamgraph.md +53 -0
  430. package/skills/lit-diagram-drawer/references/type-swimlane.md +52 -0
  431. package/skills/lit-diagram-drawer/references/type-timeline.md +52 -0
  432. package/skills/lit-diagram-drawer/references/type-tree-block-decomposition.md +57 -0
  433. package/skills/lit-diagram-drawer/references/type-tree.md +54 -0
  434. package/skills/lit-diagram-drawer/references/type-treemap.md +54 -0
  435. package/skills/lit-diagram-drawer/references/type-uml-class.md +52 -0
  436. package/skills/lit-diagram-drawer/references/type-venn.md +51 -0
  437. package/skills/lit-diagram-drawer/references/type-wardley.md +52 -0
  438. package/skills/lit-diagram-drawer/references/type-waterfall.md +54 -0
  439. package/skills/lit-diagram-drawer/references/verifier-guide.md +59 -0
  440. package/skills/lit-diagram-drawer/scripts/block-registry.mjs +43 -0
  441. package/skills/lit-diagram-drawer/scripts/brief-contract.mjs +94 -0
  442. package/skills/lit-diagram-drawer/scripts/capability-probe.mjs +132 -0
  443. package/skills/lit-diagram-drawer/scripts/check-visible-text.mjs +15 -0
  444. package/skills/lit-diagram-drawer/scripts/craft-thresholds.json +15 -0
  445. package/skills/lit-diagram-drawer/scripts/diagram-metrics.mjs +216 -0
  446. package/skills/lit-diagram-drawer/scripts/doctor.mjs +8 -0
  447. package/skills/lit-diagram-drawer/scripts/drawio-extract.mjs +214 -0
  448. package/skills/lit-diagram-drawer/scripts/excalidraw-extract.mjs +151 -0
  449. package/skills/lit-diagram-drawer/scripts/export.mjs +133 -0
  450. package/skills/lit-diagram-drawer/scripts/import-shared.mjs +130 -0
  451. package/skills/lit-diagram-drawer/scripts/mermaid-extract.mjs +173 -0
  452. package/skills/lit-diagram-drawer/scripts/office-safety.mjs +120 -0
  453. package/skills/lit-diagram-drawer/scripts/renderer-safety.mjs +46 -0
  454. package/skills/lit-diagram-drawer/scripts/test-block-registry.mjs +20 -0
  455. package/skills/lit-diagram-drawer/scripts/test-brief-contract.mjs +27 -0
  456. package/skills/lit-diagram-drawer/scripts/test-importers.mjs +119 -0
  457. package/skills/lit-diagram-drawer/scripts/test-office-safety.mjs +67 -0
  458. package/skills/lit-diagram-drawer/scripts/test-sequence-verifier.mjs +28 -0
  459. package/skills/lit-diagram-drawer/scripts/test-visual-quality.mjs +68 -0
  460. package/skills/lit-diagram-drawer/scripts/verify-all.mjs +74 -0
  461. package/skills/lit-diagram-drawer/scripts/verify-brief.mjs +47 -0
  462. package/skills/lit-diagram-drawer/scripts/verify-coverage.mjs +56 -0
  463. package/skills/lit-diagram-drawer/scripts/verify-diagram.mjs +26 -0
  464. package/skills/lit-diagram-drawer/scripts/verify-motion.mjs +12 -0
  465. package/skills/lit-diagram-drawer/scripts/verify-type.mjs +48 -0
  466. package/skills/lit-diagram-drawer/scripts/visual-quality.mjs +363 -0
  467. package/skills/lit-docx/LICENSE-MIT.txt +21 -0
  468. package/skills/lit-docx/SKILL.md +78 -0
  469. package/skills/lit-docx/references/frontmatter_schema.md +42 -0
  470. package/skills/lit-docx/references/journal_style_spec.md +17 -0
  471. package/skills/lit-docx/references/markdown_quality_checklist.md +37 -0
  472. package/skills/lit-docx/references/slop_phrase_list.yaml +58 -0
  473. package/skills/lit-docx/references/slop_rules.md +35 -0
  474. package/skills/lit-docx/requirements.in +5 -0
  475. package/skills/lit-docx/requirements.lock +289 -0
  476. package/skills/lit-docx/run.py +64 -0
  477. package/skills/lit-docx/scripts/clean_markdown.py +95 -0
  478. package/skills/lit-docx/scripts/convert_md_to_docx.py +1047 -0
  479. package/skills/lit-docx/scripts/convert_md_to_pdf.py +281 -0
  480. package/skills/lit-docx/scripts/convert_pdf.py +130 -0
  481. package/skills/lit-docx/scripts/craft-thresholds.json +11 -0
  482. package/skills/lit-docx/scripts/craft_docx.py +83 -0
  483. package/skills/lit-docx/scripts/edit_docx.py +297 -0
  484. package/skills/lit-docx/scripts/embed_images.py +78 -0
  485. package/skills/lit-docx/scripts/generate_docx_templates.py +491 -0
  486. package/skills/lit-docx/scripts/slop_lint.py +485 -0
  487. package/skills/lit-docx/scripts/visual_audit.py +41 -0
  488. package/skills/lit-docx/templates/docx/acs.docx +0 -0
  489. package/skills/lit-docx/templates/docx/elsevier.docx +0 -0
  490. package/skills/lit-docx/templates/docx/ieee.docx +0 -0
  491. package/skills/lit-docx/templates/docx/korean-generic.docx +0 -0
  492. package/skills/lit-docx/templates/docx/nature.docx +0 -0
  493. package/skills/lit-docx/templates/latex/acs/README.md +5 -0
  494. package/skills/lit-docx/templates/latex/acs/template.tex +37 -0
  495. package/skills/lit-docx/templates/latex/elsevier/README.md +5 -0
  496. package/skills/lit-docx/templates/latex/elsevier/template.tex +38 -0
  497. package/skills/lit-docx/templates/latex/ieee/README.md +5 -0
  498. package/skills/lit-docx/templates/latex/ieee/template.tex +37 -0
  499. package/skills/lit-docx/templates/latex/korean-generic/README.md +5 -0
  500. package/skills/lit-docx/templates/latex/korean-generic/template.tex +37 -0
  501. package/skills/lit-docx/templates/latex/nature/README.md +5 -0
  502. package/skills/lit-docx/templates/latex/nature/template.tex +37 -0
  503. package/skills/lit-docx/templates/registry.yaml +1366 -0
  504. package/skills/lit-humanizer/NOTICE +160 -0
  505. package/skills/lit-humanizer/SKILL.md +122 -0
  506. package/skills/lit-humanizer/assets/always-on-rule.md +9 -0
  507. package/skills/lit-humanizer/assets/report-skeleton.md +25 -0
  508. package/skills/lit-humanizer/assets/slide-text-skeleton.md +28 -0
  509. package/skills/lit-humanizer/examples/accessibility-note/after.md +7 -0
  510. package/skills/lit-humanizer/examples/accessibility-note/before.md +7 -0
  511. package/skills/lit-humanizer/examples/api-reference/after.md +9 -0
  512. package/skills/lit-humanizer/examples/api-reference/before.md +15 -0
  513. package/skills/lit-humanizer/examples/changelog/after.md +5 -0
  514. package/skills/lit-humanizer/examples/changelog/before.md +12 -0
  515. package/skills/lit-humanizer/examples/code-comments/after.md +10 -0
  516. package/skills/lit-humanizer/examples/code-comments/before.md +19 -0
  517. package/skills/lit-humanizer/examples/commit/after.md +5 -0
  518. package/skills/lit-humanizer/examples/commit/before.md +7 -0
  519. package/skills/lit-humanizer/examples/data-release/after.md +7 -0
  520. package/skills/lit-humanizer/examples/data-release/before.md +9 -0
  521. package/skills/lit-humanizer/examples/english-essay/after.md +5 -0
  522. package/skills/lit-humanizer/examples/english-essay/before.md +5 -0
  523. package/skills/lit-humanizer/examples/incident-update/after.md +7 -0
  524. package/skills/lit-humanizer/examples/incident-update/before.md +7 -0
  525. package/skills/lit-humanizer/examples/ko-essay/after.md +7 -0
  526. package/skills/lit-humanizer/examples/ko-essay/before.md +9 -0
  527. package/skills/lit-humanizer/examples/ko-report/after.md +9 -0
  528. package/skills/lit-humanizer/examples/ko-report/before.md +13 -0
  529. package/skills/lit-humanizer/examples/ko-slide/after.md +19 -0
  530. package/skills/lit-humanizer/examples/ko-slide/before.md +21 -0
  531. package/skills/lit-humanizer/examples/meeting-brief/after.md +9 -0
  532. package/skills/lit-humanizer/examples/meeting-brief/before.md +11 -0
  533. package/skills/lit-humanizer/examples/policy-faq/after.md +9 -0
  534. package/skills/lit-humanizer/examples/policy-faq/before.md +9 -0
  535. package/skills/lit-humanizer/examples/pr/after.md +15 -0
  536. package/skills/lit-humanizer/examples/pr/before.md +17 -0
  537. package/skills/lit-humanizer/examples/project-update/after.md +7 -0
  538. package/skills/lit-humanizer/examples/project-update/before.md +9 -0
  539. package/skills/lit-humanizer/examples/readme/after.md +12 -0
  540. package/skills/lit-humanizer/examples/readme/before.md +14 -0
  541. package/skills/lit-humanizer/examples/report/after.md +13 -0
  542. package/skills/lit-humanizer/examples/report/before.md +11 -0
  543. package/skills/lit-humanizer/examples/research-abstract/after.md +5 -0
  544. package/skills/lit-humanizer/examples/research-abstract/before.md +5 -0
  545. package/skills/lit-humanizer/examples/slides/after.md +19 -0
  546. package/skills/lit-humanizer/examples/slides/before.md +19 -0
  547. package/skills/lit-humanizer/examples/troubleshooting/after.md +11 -0
  548. package/skills/lit-humanizer/examples/troubleshooting/before.md +11 -0
  549. package/skills/lit-humanizer/fixtures/ko-metrics-golden.json +49 -0
  550. package/skills/lit-humanizer/fixtures/office/minimal.docx +0 -0
  551. package/skills/lit-humanizer/fixtures/office/minimal.pptx +0 -0
  552. package/skills/lit-humanizer/fixtures/pos-real.txt +26 -0
  553. package/skills/lit-humanizer/fixtures/rule-cases.json +306 -0
  554. package/skills/lit-humanizer/references/code-patterns.md +468 -0
  555. package/skills/lit-humanizer/references/deliverable-channels.md +111 -0
  556. package/skills/lit-humanizer/references/en-patterns-checklist.md +43 -0
  557. package/skills/lit-humanizer/references/en-patterns-content.md +243 -0
  558. package/skills/lit-humanizer/references/en-patterns-structure.md +375 -0
  559. package/skills/lit-humanizer/references/en-patterns.md +57 -0
  560. package/skills/lit-humanizer/references/ko-metrics.md +33 -0
  561. package/skills/lit-humanizer/references/ko-patterns-a-d.md +659 -0
  562. package/skills/lit-humanizer/references/ko-patterns-e-j.md +387 -0
  563. package/skills/lit-humanizer/references/ko-patterns.md +31 -0
  564. package/skills/lit-humanizer/references/rewrite-playbook.md +54 -0
  565. package/skills/lit-humanizer/references/taxonomy.md +153 -0
  566. package/skills/lit-humanizer/rules.json +884 -0
  567. package/skills/lit-humanizer/scripts/core.mjs +208 -0
  568. package/skills/lit-humanizer/scripts/detect.mjs +91 -0
  569. package/skills/lit-humanizer/scripts/extract_office_text.py +89 -0
  570. package/skills/lit-humanizer/scripts/guard-scan.mjs +36 -0
  571. package/skills/lit-humanizer/scripts/ko-metrics.mjs +124 -0
  572. package/skills/lit-humanizer/scripts/test-fixtures.mjs +54 -0
  573. package/skills/lit-humanizer/scripts/test-ko-metrics.mjs +27 -0
  574. package/skills/lit-pptx/FORBIDDEN_TERMS.json +55 -0
  575. package/skills/lit-pptx/NOTICE.md +3 -0
  576. package/skills/lit-pptx/SKILL.md +76 -0
  577. package/skills/lit-pptx/agents/analyst.md +49 -0
  578. package/skills/lit-pptx/agents/antithesis.md +59 -0
  579. package/skills/lit-pptx/agents/architect.md +44 -0
  580. package/skills/lit-pptx/agents/critic.md +42 -0
  581. package/skills/lit-pptx/agents/synthesizer.md +47 -0
  582. package/skills/lit-pptx/agents/thesis.md +33 -0
  583. package/skills/lit-pptx/assets/azure/circle-lg.png +0 -0
  584. package/skills/lit-pptx/assets/azure/circle-md.png +0 -0
  585. package/skills/lit-pptx/assets/azure/circle-sm.png +0 -0
  586. package/skills/lit-pptx/fonts/a2z-font/A2Z-Black.otf +0 -0
  587. package/skills/lit-pptx/fonts/a2z-font/A2Z-Bold.otf +0 -0
  588. package/skills/lit-pptx/fonts/a2z-font/A2Z-Light.otf +0 -0
  589. package/skills/lit-pptx/fonts/a2z-font/A2Z-Medium.otf +0 -0
  590. package/skills/lit-pptx/fonts/a2z-font/A2Z-Regular.otf +0 -0
  591. package/skills/lit-pptx/fonts/a2z-font/OFL.txt +94 -0
  592. package/skills/lit-pptx/fonts/a2z-font/SOURCE.md +29 -0
  593. package/skills/lit-pptx/package-lock.json +747 -0
  594. package/skills/lit-pptx/package.json +13 -0
  595. package/skills/lit-pptx/pretendard-font/LICENSE.txt +94 -0
  596. package/skills/lit-pptx/pretendard-font/public/static/LitOpenCodeSans-Bold.otf +0 -0
  597. package/skills/lit-pptx/pretendard-font/public/static/LitOpenCodeSans-Regular.otf +0 -0
  598. package/skills/lit-pptx/requirements.in +2 -0
  599. package/skills/lit-pptx/requirements.lock +285 -0
  600. package/skills/lit-pptx/run.mjs +71 -0
  601. package/skills/lit-pptx/scripts/check_ooxml.py +47 -0
  602. package/skills/lit-pptx/scripts/compile-deck.js +447 -0
  603. package/skills/lit-pptx/scripts/craft-thresholds.json +26 -0
  604. package/skills/lit-pptx/scripts/craft_extras.py +224 -0
  605. package/skills/lit-pptx/scripts/embed_fonts.py +204 -0
  606. package/skills/lit-pptx/scripts/layout_inventory.py +70 -0
  607. package/skills/lit-pptx/scripts/learn_template.py +433 -0
  608. package/skills/lit-pptx/scripts/lib/derive-palette.js +176 -0
  609. package/skills/lit-pptx/scripts/lib/directive-parser.js +244 -0
  610. package/skills/lit-pptx/scripts/lib/font-map.js +79 -0
  611. package/skills/lit-pptx/scripts/lib/gen-bg.js +85 -0
  612. package/skills/lit-pptx/scripts/lib/gen-gradient-assets.js +36 -0
  613. package/skills/lit-pptx/scripts/lib/layout-resolver.js +737 -0
  614. package/skills/lit-pptx/scripts/lib/markdown-loader.js +136 -0
  615. package/skills/lit-pptx/scripts/lib/render-adapter-html.js +364 -0
  616. package/skills/lit-pptx/scripts/lib/render-adapter-pptx.js +1848 -0
  617. package/skills/lit-pptx/scripts/lib/slide-ast.js +534 -0
  618. package/skills/lit-pptx/scripts/lib/spec-validator.js +94 -0
  619. package/skills/lit-pptx/scripts/lib/template-registry.js +355 -0
  620. package/skills/lit-pptx/scripts/qa_deck.py +773 -0
  621. package/skills/lit-pptx/scripts/validate_pptx.py +206 -0
  622. package/skills/lit-pptx/specs/markdown-slide-spec-v1.md +251 -0
  623. package/skills/lit-pptx/specs/markdown-slide-spec-v2.md +223 -0
  624. package/skills/lit-pptx/specs/slide-ast-v1.schema.json +229 -0
  625. package/skills/lit-pptx/specs/slide-ast-v2.schema.json +144 -0
  626. package/skills/lit-pptx/specs/template-enrollment-contract.md +379 -0
  627. package/skills/lit-pptx/templates/bauhaus_light.css +4 -0
  628. package/skills/lit-pptx/templates/boilerplate_professional.css +508 -0
  629. package/skills/lit-pptx/templates/enrolled/AZURE-A2Z/capabilities.yaml +146 -0
  630. package/skills/lit-pptx/templates/enrolled/AZURE-A2Z/layout-mapping.yaml +454 -0
  631. package/skills/lit-pptx/templates/enrolled/AZURE-A2Z/template.yaml +37 -0
  632. package/skills/lit-pptx/templates/enrolled/AZURE-PRO/capabilities.yaml +154 -0
  633. package/skills/lit-pptx/templates/enrolled/AZURE-PRO/layout-mapping.yaml +483 -0
  634. package/skills/lit-pptx/templates/enrolled/AZURE-PRO/template.yaml +37 -0
  635. package/skills/lit-pptx/templates/enrolled/BOILERPLATE-A2Z/capabilities.yaml +179 -0
  636. package/skills/lit-pptx/templates/enrolled/BOILERPLATE-A2Z/layout-mapping.yaml +299 -0
  637. package/skills/lit-pptx/templates/enrolled/BOILERPLATE-A2Z/template.yaml +45 -0
  638. package/skills/lit-pptx/templates/enrolled/BOILERPLATE-PRETENDARD/capabilities.yaml +181 -0
  639. package/skills/lit-pptx/templates/enrolled/BOILERPLATE-PRETENDARD/layout-mapping.yaml +299 -0
  640. package/skills/lit-pptx/templates/enrolled/BOILERPLATE-PRETENDARD/template.yaml +44 -0
  641. package/skills/lit-scientific-visualization/SKILL.md +2 -0
  642. package/skills/lit-typographic-motion/NOTICE +23 -0
  643. package/skills/lit-typographic-motion/SKILL.md +77 -0
  644. package/skills/lit-typographic-motion/THIRD_PARTY_NOTICES +25 -0
  645. package/skills/lit-typographic-motion/audio-analysis.py +52 -0
  646. package/skills/lit-typographic-motion/engine/browser.mjs +83 -0
  647. package/skills/lit-typographic-motion/engine/constants.mjs +177 -0
  648. package/skills/lit-typographic-motion/engine/contrast.mjs +101 -0
  649. package/skills/lit-typographic-motion/engine/encode.mjs +46 -0
  650. package/skills/lit-typographic-motion/engine/flash.mjs +216 -0
  651. package/skills/lit-typographic-motion/engine/look.mjs +166 -0
  652. package/skills/lit-typographic-motion/engine/page/common.js +105 -0
  653. package/skills/lit-typographic-motion/engine/page/engine.js +451 -0
  654. package/skills/lit-typographic-motion/engine/page/gl.js +213 -0
  655. package/skills/lit-typographic-motion/engine/page/lines.js +88 -0
  656. package/skills/lit-typographic-motion/engine/page/passes.js +144 -0
  657. package/skills/lit-typographic-motion/engine/page/post.js +119 -0
  658. package/skills/lit-typographic-motion/engine/page/scenes.js +187 -0
  659. package/skills/lit-typographic-motion/engine/page/type.js +321 -0
  660. package/skills/lit-typographic-motion/engine/png.mjs +139 -0
  661. package/skills/lit-typographic-motion/engine/sound.mjs +291 -0
  662. package/skills/lit-typographic-motion/engine/stage/capture.mjs +133 -0
  663. package/skills/lit-typographic-motion/engine/stage/clock.js +171 -0
  664. package/skills/lit-typographic-motion/engine/stage/frame-worker.mjs +47 -0
  665. package/skills/lit-typographic-motion/engine/stage/gate.mjs +119 -0
  666. package/skills/lit-typographic-motion/engine/stage/qa-page.js +158 -0
  667. package/skills/lit-typographic-motion/engine/stage/qa.mjs +208 -0
  668. package/skills/lit-typographic-motion/engine/stage/render.mjs +418 -0
  669. package/skills/lit-typographic-motion/engine/stage/scan.mjs +162 -0
  670. package/skills/lit-typographic-motion/engine/stage/stage-kit.js +310 -0
  671. package/skills/lit-typographic-motion/engine/stills.mjs +60 -0
  672. package/skills/lit-typographic-motion/engine/text.mjs +126 -0
  673. package/skills/lit-typographic-motion/engine/timing.mjs +289 -0
  674. package/skills/lit-typographic-motion/engine/treatment.mjs +254 -0
  675. package/skills/lit-typographic-motion/fonts/Archivo-100-400.ttf +0 -0
  676. package/skills/lit-typographic-motion/fonts/Archivo-100-700.ttf +0 -0
  677. package/skills/lit-typographic-motion/fonts/Archivo-100-900.ttf +0 -0
  678. package/skills/lit-typographic-motion/fonts/Archivo-125-400.ttf +0 -0
  679. package/skills/lit-typographic-motion/fonts/Archivo-125-700.ttf +0 -0
  680. package/skills/lit-typographic-motion/fonts/Archivo-125-900.ttf +0 -0
  681. package/skills/lit-typographic-motion/fonts/Archivo-75-400.ttf +0 -0
  682. package/skills/lit-typographic-motion/fonts/Archivo-75-700.ttf +0 -0
  683. package/skills/lit-typographic-motion/fonts/Archivo-75-900.ttf +0 -0
  684. package/skills/lit-typographic-motion/fonts/Archivo-OFL.txt +93 -0
  685. package/skills/lit-typographic-motion/fonts/Silkscreen-Bold.ttf +0 -0
  686. package/skills/lit-typographic-motion/fonts/Silkscreen-OFL.txt +93 -0
  687. package/skills/lit-typographic-motion/fonts/Silkscreen-Regular.ttf +0 -0
  688. package/skills/lit-typographic-motion/fonts/VT323-OFL.txt +93 -0
  689. package/skills/lit-typographic-motion/fonts/VT323-Regular.ttf +0 -0
  690. package/skills/lit-typographic-motion/fonts/pins.json +44 -0
  691. package/skills/lit-typographic-motion/fonts/stroke/CREDITS +52 -0
  692. package/skills/lit-typographic-motion/fonts/stroke/EMSAllure.svg +216 -0
  693. package/skills/lit-typographic-motion/fonts/stroke/EMSFelix.svg +216 -0
  694. package/skills/lit-typographic-motion/fonts/stroke/EMSOsmotron.svg +216 -0
  695. package/skills/lit-typographic-motion/fonts/stroke/EMSReadability.svg +216 -0
  696. package/skills/lit-typographic-motion/fonts/stroke/EMSTech.svg +217 -0
  697. package/skills/lit-typographic-motion/fonts/stroke/OFL.txt +85 -0
  698. package/skills/lit-typographic-motion/gate.mjs +593 -0
  699. package/skills/lit-typographic-motion/package-lock.json +78 -0
  700. package/skills/lit-typographic-motion/package.json +11 -0
  701. package/skills/lit-typographic-motion/probe.mjs +74 -0
  702. package/skills/lit-typographic-motion/references/authoring.md +110 -0
  703. package/skills/lit-typographic-motion/references/craft-loop.md +110 -0
  704. package/skills/lit-typographic-motion/references/runtime.md +88 -0
  705. package/skills/lit-typographic-motion/references/stage.md +164 -0
  706. package/skills/lit-typographic-motion/references/style-bibles.md +88 -0
  707. package/skills/lit-typographic-motion/references/treatment.md +143 -0
  708. package/skills/lit-typographic-motion/references/type-craft.md +55 -0
  709. package/skills/lit-typographic-motion/render.mjs +654 -0
  710. package/skills/lit-typographic-motion/requirements-audio.in +1 -0
  711. package/skills/lit-typographic-motion/requirements-audio.txt +790 -0
  712. package/skills/lit-typographic-motion/runtime.mjs +259 -0
  713. package/skills/lit-typographic-motion/word-timing-models.json +25 -0
  714. package/skills/litresearch/SKILL.md +41 -12
  715. package/skills/managed-skill-manifest.json +2367 -63
  716. package/skills/skill-rename-aliases.json +6 -1
  717. package/tools/check-pack-payload.mjs +22 -1
  718. package/tools/check-payload-substance.mjs +2 -2
  719. package/tools/payload-reference-exemptions.json +4 -0
  720. package/tools/payload-substance-allowlist.json +2 -3
  721. package/tools/payload-substance-parity.json +7 -7
  722. package/tools/version-manifests.json +4 -4
  723. package/skills/lit-korean/SKILL.md +0 -231
@@ -0,0 +1,593 @@
1
+ #!/usr/bin/env node
2
+ // lit-typographic-motion numeric QA gate (spec Section C, MO-D-02..04, and every measurable HARD or
3
+ // CAP row of the rule index). It reads a finished output directory: manifest.json, render.jsonl (per
4
+ // frame pass lines, frame lines and the preview audit records), the .run/ records (brief copy,
5
+ // pre-flight, contrast samples, determinism, perf) and the exports. It writes gate-report.txt, then
6
+ // promotes or withholds the exports (MO-C-16).
7
+ import { spawnSync } from "node:child_process";
8
+ import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
9
+ import path from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+ import { EXIT, FRAME, chromeFlagRungs, flashEventThreshold, isSoftwareRenderer, limits, postOverrideTable, provisionalRules, presets } from "./engine/constants.mjs";
12
+ import { countFlashes } from "./engine/flash.mjs";
13
+ import { bigEnough, boxContrast, hueClusters, warpMask } from "./engine/contrast.mjs";
14
+ import { decodePng } from "./engine/png.mjs";
15
+ import { eojeols, passSeed, readingFloor, selectPreset, unitCounts } from "./engine/text.mjs";
16
+ import { pinnedSampleTimes } from "./engine/timing.mjs";
17
+ import { checkStageRun, formatStageReport } from "./engine/stage/gate.mjs";
18
+ import { soundChecks } from "./engine/sound.mjs";
19
+ import { doneState, formatDone } from "./engine/look.mjs";
20
+
21
+ export const exportNames = ["film.mp4", "preview.webp", "preview.gif", "poster.png", "reduced-motion.png"];
22
+ const isShot = (entry) => entry.kind === "line" || entry.kind === "scene";
23
+ const pass = (detail = "") => ({ pass: true, detail });
24
+ const fail = (detail) => ({ pass: false, detail });
25
+ const eps = 1e-6;
26
+
27
+ export function readRun(dir) {
28
+ const root = path.resolve(dir);
29
+ const manifest = JSON.parse(readFileSync(path.join(root, "manifest.json"), "utf8"));
30
+ const lines = existsSync(path.join(root, "render.jsonl")) ? readFileSync(path.join(root, "render.jsonl"), "utf8").split("\n").filter(Boolean).map((line) => JSON.parse(line)) : [];
31
+ const json = (name) => (existsSync(path.join(root, ".run", name)) ? JSON.parse(readFileSync(path.join(root, ".run", name), "utf8")) : null);
32
+ return {
33
+ root, manifest,
34
+ passLines: lines.filter((line) => line.stream === undefined && line.pass !== null && line.pass !== undefined),
35
+ frameLines: lines.filter((line) => line.stream === undefined && line.pass === null),
36
+ previewLines: lines.filter((line) => line.stream === "preview"),
37
+ brief: json("brief.json"), preflight: json("preflight.json"), samples: json("samples.json"),
38
+ determinism: json("determinism.json"), perf: json("perf.json"), still: json("still.json")
39
+ };
40
+ }
41
+
42
+ // ---- timeline rules, shared with the renderer's pre-flight (MO-C-07/08, MO-A-11..16, MO-A-41a) ----
43
+ function gridBeats(manifest) {
44
+ if (Array.isArray(manifest.beatGrid) && manifest.beatGrid.length >= 2) {
45
+ const intervals = manifest.beatGrid.slice(1).map((t, i) => t - manifest.beatGrid[i]).sort((a, b) => a - b);
46
+ return { beat: intervals[Math.floor(intervals.length / 2)], onGrid: (t) => t < eps || manifest.beatGrid.some((b) => Math.abs(b - t) <= 1 / manifest.fps + eps) || t > manifest.beatGrid.at(-1) };
47
+ }
48
+ const beat = 60 / manifest.bpm;
49
+ return { beat, onGrid: (t) => Math.abs(t / beat - Math.round(t / beat)) * beat <= 1 / manifest.fps + eps };
50
+ }
51
+
52
+ export function timelineChecks(manifest) {
53
+ const checks = {};
54
+ const timeline = manifest.timeline ?? [];
55
+ const fps = manifest.fps;
56
+ const required = ["id", "sceneId", "shotIndex", "start", "end", "holdSec", "kind", "text", "script", "beatSec"];
57
+ const malformed = timeline.find((entry) => required.some((key) => entry[key] === undefined) || Math.abs(entry.holdSec - (entry.end - entry.start)) > 1e-4 || !["line", "word", "reveal", "scene"].includes(entry.kind));
58
+ checks["MO-A-41a"] = timeline.length && !malformed ? pass(`${timeline.length} entries`) : fail(malformed ? `malformed entry ${malformed.id ?? "?"}` : "empty timeline");
59
+ let tightest = null;
60
+ const under = [];
61
+ const cps = [];
62
+ for (const unit of timeline) {
63
+ const floor = readingFloor(unit.text, unit.kind);
64
+ const slack = unit.holdSec - floor;
65
+ if (!tightest || slack < tightest.slack) tightest = { unit, floor, slack };
66
+ if (unit.holdSec < floor - 1 / fps) under.push(`"${unit.text}" (${unit.kind}) ${unit.holdSec.toFixed(2)}s < ${floor.toFixed(2)}s`);
67
+ if ((unit.kind === "line" || unit.kind === "scene") && unit.holdSec > 0 && unitCounts(unit.text).C / unit.holdSec > limits.latinCharsPerSecond + eps) cps.push(`"${unit.text}" ${(unitCounts(unit.text).C / unit.holdSec).toFixed(1)} cps`);
68
+ }
69
+ const detail = tightest ? `tightest unit "${tightest.unit.text.replace(/\n/gu, " / ")}" (${tightest.unit.kind}) hold ${tightest.unit.holdSec.toFixed(2)}s vs floor ${tightest.floor.toFixed(2)}s` : "no timeline";
70
+ checks["MO-C-07/08"] = under.length || cps.length ? fail(`${[...under, ...cps].slice(0, 3).join("; ")} — ${detail}`) : pass(detail);
71
+ const { beat, onGrid } = gridBeats(manifest);
72
+ const offBeat = timeline.filter((entry) => Math.abs(entry.start - entry.beatSec) > 1 / fps + eps || !onGrid(entry.beatSec));
73
+ checks["MO-A-15"] = offBeat.length ? fail(`${offBeat[0].id} starts ${(Math.abs(offBeat[0].start - offBeat[0].beatSec) * 1000).toFixed(1)} ms from its beat`) : pass(`every start within 1 frame of a grid beat (beat ${beat.toFixed(3)}s)`);
74
+ const short = timeline.filter(isShot).filter((shot) => shot.holdSec < limits.minSceneBeats * beat - 1 / fps);
75
+ checks["MO-A-16"] = short.length ? fail(`${short[0].id} holds ${short[0].holdSec.toFixed(2)}s < ${limits.minSceneBeats} beats`) : pass(`every shot >= ${limits.minSceneBeats} beats`);
76
+ const split = [];
77
+ for (const shot of timeline.filter(isShot)) {
78
+ if (shot.kind !== "line") continue;
79
+ const tokens = eojeols(shot.text);
80
+ const reveals = timeline.filter((entry) => entry.kind === "reveal" && entry.sceneId === shot.sceneId && entry.shotIndex === shot.shotIndex);
81
+ let cursor = 0;
82
+ for (const reveal of reveals) {
83
+ const parts = eojeols(reveal.text);
84
+ const expected = tokens.slice(cursor, cursor + parts.length);
85
+ if (parts.join(" ") !== expected.join(" ")) split.push(`${reveal.id} "${reveal.text}"`);
86
+ cursor += parts.length;
87
+ }
88
+ }
89
+ checks["MO-A-13"] = split.length ? fail(`reveal step splits a 어절: ${split[0]}`) : pass("reveal steps and breaks fall on 어절 boundaries");
90
+ return checks;
91
+ }
92
+
93
+ // ---- helpers over the log ----
94
+ function eventsFromLog(frameLines) {
95
+ const events = [];
96
+ let flashHigh = false, invert = false;
97
+ for (const line of frameLines) {
98
+ for (const event of line.events ?? []) events.push({ ...event, frame: line.frame });
99
+ const p = line.post ?? {};
100
+ if ((p.flash ?? 0) > flashEventThreshold && !flashHigh) events.push({ kind: "flash", frame: line.frame, sceneId: line.sceneId, shotIndex: line.shotIndex });
101
+ flashHigh = (p.flash ?? 0) > flashEventThreshold;
102
+ if (Boolean(p.invert) !== invert && line.frame > 0) events.push({ kind: "invert", frame: line.frame, sceneId: line.sceneId, shotIndex: line.shotIndex });
103
+ invert = Boolean(p.invert);
104
+ }
105
+ return events;
106
+ }
107
+
108
+ function sampleTimesOk(line, manifest) {
109
+ const expected = pinnedSampleTimes(line.frame, manifest.samples, manifest.shutter, manifest.fps);
110
+ return Array.isArray(line.sampleTimes) && line.sampleTimes.length === expected.length && line.sampleTimes.every((t, i) => Math.abs(t - expected[i]) < 1e-9);
111
+ }
112
+
113
+ function probeVideo(file) {
114
+ const probe = spawnSync("ffprobe", ["-v", "error", "-select_streams", "v:0", "-show_entries",
115
+ "stream=codec_name,width,height,r_frame_rate,pix_fmt,color_range,color_space,color_transfer,color_primaries:format=duration", "-of", "json", file], { encoding: "utf8" });
116
+ if (probe.status !== 0) return { error: (probe.stderr || probe.error?.message || "ffprobe failed").trim() };
117
+ const json = JSON.parse(probe.stdout);
118
+ return { ...json.streams?.[0], duration: Number(json.format?.duration) };
119
+ }
120
+
121
+ export function locateExport(root, name) {
122
+ for (const candidate of [path.join(root, name), path.join(root, ".run", name), path.join(root, "withheld", name)]) if (existsSync(candidate)) return candidate;
123
+ return null;
124
+ }
125
+
126
+ // ---- the full gate ----
127
+ export function checkRun(dir, options = {}) {
128
+ const run = readRun(dir);
129
+ const { manifest, passLines, frameLines, previewLines } = run;
130
+ const fps = manifest.fps;
131
+ const frameCount = Math.round(manifest.durationSec * fps);
132
+ const timeline = manifest.timeline ?? [];
133
+ const shots = timeline.filter(isShot);
134
+ const look = presets[manifest.presetId];
135
+ const checks = {};
136
+ const warnings = [...(manifest.warnings ?? [])];
137
+ const byFramePass = new Map(passLines.map((line) => [`${line.frame}:${line.pass}`, line]));
138
+ const frameByIndex = new Map(frameLines.map((line) => [line.frame, line]));
139
+ const shotOfFrame = (frame) => shots.find((shot) => frame >= Math.round(shot.start * fps) && frame < Math.round(shot.end * fps)) ?? shots.at(-1);
140
+
141
+ // MO-C-01 / MO-SH-00 / 00a / 00b: every range has a log line on every frame, and the union of
142
+ // ranges that actually drew covers every output frame.
143
+ const covered = new Uint8Array(frameCount);
144
+ let continuity = null;
145
+ for (const range of manifest.passRanges ?? []) {
146
+ for (let frame = range.frameStart; frame <= range.frameEnd; frame++) {
147
+ const line = byFramePass.get(`${frame}:${range.pass}`);
148
+ if (!line) { continuity ??= `${range.pass}@${range.sceneId}#${range.shotIndex} has no log line at frame ${frame}`; continue; }
149
+ if (line.draws >= 1 && frame < frameCount) covered[frame] = 1;
150
+ }
151
+ }
152
+ const gap = covered.findIndex((value) => !value);
153
+ const missingFrameLine = Array.from({ length: frameCount }, (_, i) => i).find((i) => !frameByIndex.has(i));
154
+ checks["MO-C-01"] = !(manifest.passRanges ?? []).length ? fail("manifest lists no GLSL pass")
155
+ : continuity ? fail(continuity)
156
+ : gap >= 0 ? fail(`frame ${gap} has no look-library pass with draws >= 1`)
157
+ : missingFrameLine !== undefined ? fail(`frame ${missingFrameLine} has no frame line`)
158
+ : pass(`${frameCount}/${frameCount} frames covered by a pass that drew`);
159
+
160
+ const seedErrors = [];
161
+ for (const range of manifest.passRanges ?? []) {
162
+ const expected = range.pass === "swiss-grid" ? null : passSeed(manifest.seed, range.sceneId, range.shotIndex, range.pass);
163
+ if (range.seed !== expected) { seedErrors.push(`${range.pass}@${range.sceneId}#${range.shotIndex} seed ${range.seed} != ${expected}`); continue; }
164
+ if (expected === null) continue;
165
+ for (let frame = range.frameStart; frame <= range.frameEnd; frame++) {
166
+ const logged = byFramePass.get(`${frame}:${range.pass}`)?.uniforms?.u_seed;
167
+ if (logged !== undefined && logged !== expected) { seedErrors.push(`${range.pass} frame ${frame} u_seed ${logged} != ${expected}`); break; }
168
+ }
169
+ }
170
+ checks["MO-SH-01"] = seedErrors.length ? fail(seedErrors[0]) : pass("every pass seed = fnv1a32(runSeed:sceneId:shotIndex:pass)");
171
+
172
+ // MO-C-02 / MO-A-04 / MO-SH-09 / MO-A-51
173
+ const software = isSoftwareRenderer(manifest.renderer);
174
+ const labelled = (manifest.warnings ?? []).some((w) => /software-rendered, --samples lowered/u.test(w));
175
+ checks["MO-C-02"] = !manifest.renderer || /NO_WEBGL2/u.test(manifest.renderer) ? fail("webgl2: false")
176
+ : manifest.softwareRenderer !== software ? fail(`softwareRenderer flag ${manifest.softwareRenderer} disagrees with renderer "${manifest.renderer}"`)
177
+ : software && !labelled ? fail(`software renderer "${manifest.renderer}" is not labelled`)
178
+ : pass(`${software ? "software (labelled)" : "hardware"} — ${manifest.renderer}`);
179
+ checks["MO-A-04"] = software && manifest.samples !== 1 ? fail(`software GL with --samples ${manifest.samples}`) : pass(software ? "software GL, samples 1" : "hardware GL");
180
+ const downgradeErrors = [];
181
+ for (const range of manifest.passRanges ?? []) {
182
+ const affected = range.pass === "tidal-gradient" || range.pass === "crt";
183
+ if (software && affected && !range.downgraded) downgradeErrors.push(`${range.pass}@${range.sceneId} not marked downgraded`);
184
+ if (software && range.pass === "tidal-gradient" && range.params.octaves !== Math.max(3, Math.floor(presets.tidal.params["tidal-gradient"].octaves / 2))) downgradeErrors.push(`tidal-gradient octaves ${range.params.octaves}`);
185
+ if (software && range.pass === "crt" && range.params.persistenceEnabled) downgradeErrors.push("crt persistence left on under software GL");
186
+ if (!software && range.downgraded) downgradeErrors.push(`${range.pass}@${range.sceneId} downgraded on a hardware renderer`);
187
+ }
188
+ checks["MO-SH-09"] = downgradeErrors.length ? fail(downgradeErrors[0]) : pass(software ? "downgrade formula applied" : "no downgrade needed");
189
+ const rungs = chromeFlagRungs().map((rung) => rung.flags.join(" "));
190
+ checks["MO-A-51"] = rungs.includes((manifest.chromeFlags ?? []).join(" ")) ? pass(manifest.chromeFlags.join(" ")) : fail(`chromeFlags is not a ladder rung: ${(manifest.chromeFlags ?? []).join(" ")}`);
191
+
192
+ // MO-C-03 / MO-SH-04 / MO-SH-04a
193
+ const master = countFlashes(frameLines.sort((a, b) => a.frame - b.frame).map((line) => line.transitions ?? {}), fps, false);
194
+ const previewFps = manifest.preview?.fps ?? fps;
195
+ const preview = previewLines.length ? countFlashes(previewLines.sort((a, b) => a.previewFrame - b.previewFrame).map((line) => line.transitions ?? {}), previewFps, true) : null;
196
+ const general = Math.max(master.general, preview?.general ?? 0), red = Math.max(master.red, preview?.red ?? 0);
197
+ const worstSource = (preview && (preview.general > master.general || preview.red > master.red)) ? { name: "preview", r: preview, fps: previewFps } : { name: "master", r: master, fps };
198
+ const worstStart = worstSource.r.worstWindow.general.flashes >= worstSource.r.worstWindow.red.flashes ? worstSource.r.worstWindow.general : worstSource.r.worstWindow.red;
199
+ const flashDetail = `worst window ${general} general / ${red} red (limit ${limits.flashLimitGeneral} / ${limits.flashLimitRed}); ${worstSource.name} window at frame ${worstStart.start} (${(worstStart.start / worstSource.fps).toFixed(2)}s) transitions ${worstStart.transitions.join(" ") || "none"}`;
200
+ checks["MO-C-03"] = !previewLines.length && options.requirePreview !== false ? fail(`preview frames were not audited; ${flashDetail}`)
201
+ : general <= limits.flashLimitGeneral && red <= limits.flashLimitRed ? pass(flashDetail) : fail(flashDetail);
202
+ const stepFrame = frameLines.find((line) => line.fullStep);
203
+ const stepPreview = previewLines.find((line) => line.fullStep);
204
+ checks["MO-SH-04a"] = stepFrame || stepPreview ? fail(`full-frame luminance step at ${stepFrame ? `frame ${stepFrame.frame}` : `preview frame ${stepPreview.previewFrame}`}`) : pass("no full-frame luminance step in any frame pair");
205
+
206
+ // MO-SH-03 / MO-A-58
207
+ const events = eventsFromLog(frameLines);
208
+ let crowded = null;
209
+ for (const shot of shots) {
210
+ const times = events.filter((event) => event.sceneId === shot.sceneId && event.shotIndex === shot.shotIndex).map((event) => event.frame / fps).sort((a, b) => a - b);
211
+ for (let i = 0; i + limits.eventsPerSecondPerShot < times.length; i++) {
212
+ if (times[i + limits.eventsPerSecondPerShot] - times[i] < 1 - eps) { crowded = `${shot.id}: ${limits.eventsPerSecondPerShot + 1} events within ${(times[i + limits.eventsPerSecondPerShot] - times[i]).toFixed(2)}s from ${times[i].toFixed(2)}s`; break; }
213
+ }
214
+ if (crowded) break;
215
+ }
216
+ checks["MO-SH-03"] = crowded ? fail(crowded) : pass(`${events.length} events, at most ${limits.eventsPerSecondPerShot} in any 1 s window per shot`);
217
+ const overrideErrors = [];
218
+ let lastInvertChange = null;
219
+ const { beat } = gridBeats(manifest);
220
+ for (const line of frameLines) {
221
+ for (const [field, rule] of Object.entries(postOverrideTable)) {
222
+ const value = line.post?.[field];
223
+ if (value === undefined) continue;
224
+ if (rule.kind === "number" && (typeof value !== "number" || value < rule.min || (rule.exclusiveMin && value <= rule.min) || value > rule.max)) overrideErrors.push(`frame ${line.frame} ${field}=${value}`);
225
+ if (rule.kind === "boolean" && typeof value !== "boolean") overrideErrors.push(`frame ${line.frame} invert must be boolean`);
226
+ if (rule.kind === "pair" && !(Array.isArray(value) && value.length === 2 && value.every(Number.isFinite))) overrideErrors.push(`frame ${line.frame} shake must be a pair`);
227
+ }
228
+ }
229
+ for (const event of events.filter((e) => e.kind === "invert")) {
230
+ const shot = shotOfFrame(event.frame);
231
+ if (event.frame !== Math.round(shot.start * fps)) overrideErrors.push(`invert changes at frame ${event.frame}, not on a cut`);
232
+ if (lastInvertChange !== null && (event.frame - lastInvertChange) / fps < limits.minSceneBeats * beat - 1 / fps) overrideErrors.push(`invert held ${((event.frame - lastInvertChange) / fps).toFixed(2)}s < ${limits.minSceneBeats} beats`);
233
+ lastInvertChange = event.frame;
234
+ }
235
+ checks["MO-A-58"] = overrideErrors.length ? fail(overrideErrors[0]) : pass("every override inside its range; invert only on cuts");
236
+
237
+ // MO-SH-05..08, MO-SH-10, MO-A-05
238
+ const passErrors = [];
239
+ for (const range of manifest.passRanges ?? []) {
240
+ const p = range.params ?? {};
241
+ const shot = shots.find((s) => s.sceneId === range.sceneId && s.shotIndex === range.shotIndex);
242
+ if (range.pass === "glitch") {
243
+ if (!(p.hitRatePerSecRealized <= limits.glitchHitRateCap)) passErrors.push(["MO-SH-05", `glitch hit rate ${p.hitRatePerSecRealized}/s > ${limits.glitchHitRateCap}`]);
244
+ if (!(p.areaCapPct <= limits.glitchAreaCapPct) || !(p.maxAreaPctRealized <= limits.glitchAreaCapPct)) passErrors.push(["MO-SH-05", `glitch area ${p.maxAreaPctRealized ?? p.areaCapPct}% > ${limits.glitchAreaCapPct}%`]);
245
+ const hits = events.filter((e) => e.kind === "glitch" && e.sceneId === range.sceneId && e.shotIndex === range.shotIndex).map((e) => e.frame / fps);
246
+ for (let i = 0; i + 2 < hits.length; i++) if (hits[i + 2] - hits[i] < 1 - eps) passErrors.push(["MO-SH-05", `3 glitch hits within 1 s at ${hits[i].toFixed(2)}s`]);
247
+ }
248
+ if (range.pass === "tidal-gradient") {
249
+ if (!(p.surgeAttackSec >= limits.surgeEdgeFloorSec) || !(p.surgeDecaySec >= limits.surgeEdgeFloorSec)) passErrors.push(["MO-SH-06", `surge attack ${p.surgeAttackSec}s / decay ${p.surgeDecaySec}s under ${limits.surgeEdgeFloorSec}s`]);
250
+ if (!(p.surgeCapPerSec <= limits.surgeRateCap)) passErrors.push(["MO-SH-06", `surge cap ${p.surgeCapPerSec}/s > ${limits.surgeRateCap}`]);
251
+ const surges = events.filter((e) => e.kind === "surge" && e.sceneId === range.sceneId && e.shotIndex === range.shotIndex).map((e) => e.frame / fps);
252
+ for (let i = 0; i + 2 < surges.length; i++) if (surges[i + 2] - surges[i] < 1 - eps) passErrors.push(["MO-SH-06", `3 surges within 1 s at ${surges[i].toFixed(2)}s`]);
253
+ for (const e of events.filter((ev) => ev.kind === "surge" && ev.sceneId === range.sceneId)) if (!(e.attackSec >= limits.surgeEdgeFloorSec && e.decaySec >= limits.surgeEdgeFloorSec)) passErrors.push(["MO-SH-06", `surge at frame ${e.frame} has attack ${e.attackSec}s / decay ${e.decaySec}s`]);
254
+ }
255
+ if (range.pass === "crt") {
256
+ let peak = p.flickerAmpRealized ?? 0;
257
+ for (let frame = range.frameStart; frame <= range.frameEnd; frame++) peak = Math.max(peak, byFramePass.get(`${frame}:crt`)?.uniforms?.u_flickerAmp ?? 0);
258
+ if (peak > limits.crtFlickerCap + eps) passErrors.push(["MO-SH-07", `CRT flicker ${peak} > ${limits.crtFlickerCap}`]);
259
+ if (p.persistenceEnabled && !shot?.stateful) passErrors.push(["MO-A-05", `persistence on non-stateful scene ${range.sceneId}#${range.shotIndex}`]);
260
+ }
261
+ if (range.pass === "dither") {
262
+ for (let frame = range.frameStart; frame <= range.frameEnd; frame++) {
263
+ const logged = byFramePass.get(`${frame}:dither`)?.uniforms?.u_seed;
264
+ if (logged !== undefined && logged !== range.seed) { passErrors.push(["MO-SH-08", `dither reseeded inside ${range.sceneId}#${range.shotIndex} at frame ${frame}`]); break; }
265
+ }
266
+ }
267
+ if (range.pass === "swiss-grid") {
268
+ if (p.showGuides !== false) passErrors.push(["MO-SH-10", `showGuides ${p.showGuides} in ${range.sceneId}`]);
269
+ for (let frame = range.frameStart; frame <= range.frameEnd; frame++) if (byFramePass.get(`${frame}:swiss-grid`)?.uniforms?.u_showGuides === true) { passErrors.push(["MO-SH-10", `showGuides true at frame ${frame}`]); break; }
270
+ }
271
+ }
272
+ for (const id of ["MO-SH-05", "MO-SH-06", "MO-SH-07", "MO-SH-08", "MO-SH-10", "MO-A-05"]) {
273
+ const found = passErrors.find(([rule]) => rule === id);
274
+ checks[id] = found ? fail(found[1]) : pass();
275
+ }
276
+
277
+ // Type geometry rules (MO-C-04/05/25/26/27, MO-FT-04, MO-A-33, MO-A-35, MO-A-13 line breaks)
278
+ const boxes = frameLines.flatMap((line) => (line.textBoxes ?? []).map((box) => ({ ...box, frame: line.frame })));
279
+ const graphics = frameLines.flatMap((line) => (line.graphics ?? []).map((g) => ({ ...g, frame: line.frame })));
280
+ const titleViolations = boxes.filter((b) => b.bbox && (b.bbox[0] < limits.titleSafeX - eps || b.bbox[1] < limits.titleSafeY - eps || b.bbox[2] > FRAME.width - limits.titleSafeX + eps || b.bbox[3] > FRAME.height - limits.titleSafeY + eps));
281
+ const overrun = (b) => Math.max(limits.titleSafeX - b.bbox[0], limits.titleSafeY - b.bbox[1], b.bbox[2] - (FRAME.width - limits.titleSafeX), b.bbox[3] - (FRAME.height - limits.titleSafeY)).toFixed(1);
282
+ checks["MO-C-04"] = titleViolations.length ? fail(`violations: ${[...new Map(titleViolations.map((b) => [b.elementId, b])).values()].slice(0, 3).map((b) => `${b.text.replace(/\n/gu, " / ")}@${b.frame}:${overrun(b)} px`).join(", ")}`) : pass("violations: none");
283
+ const actionViolations = graphics.filter((g) => g.bbox && (g.bbox[0] < limits.actionSafeX - eps || g.bbox[1] < limits.actionSafeY - eps || g.bbox[2] > FRAME.width - limits.actionSafeX + eps || g.bbox[3] > FRAME.height - limits.actionSafeY + eps));
284
+ checks["MO-C-05"] = actionViolations.length ? fail(`${actionViolations[0].elementId} at frame ${actionViolations[0].frame} crosses the 95% action-safe border`) : pass(`${new Set(graphics.map((g) => g.elementId)).size} graphic elements inside action-safe`);
285
+ const trackingErrors = [], hangulErrors = [], outlineErrors = [], leadingErrors = [], measureErrors = [], measureNotes = [], breakErrors = [];
286
+ const pairFiles = ["LitOpenCodeSans-Regular.otf", "LitOpenCodeSans-Bold.otf", "Galmuri9.ttf", "Pretendard-Regular.otf"];
287
+ for (const box of boxes) {
288
+ for (const run of box.runs ?? []) {
289
+ if (run.script === "latin" && box.voice === "display" && run.trackingEm < limits.displayTrackingFloorEm - eps) trackingErrors.push(`"${box.text}" display tracking ${run.trackingEm}em @${box.frame}`);
290
+ if (run.script === "latin" && box.voice !== "display" && run.trackingEm < -eps) trackingErrors.push(`"${box.text}" ${box.voice} voice tracking ${run.trackingEm}em @${box.frame}`);
291
+ if (run.script === "hangul") {
292
+ if (Math.abs(run.trackingEm) > eps || run.widthPct !== 100) hangulErrors.push(["MO-FT-04", `Hangul run "${run.text}" tracking ${run.trackingEm}em width ${run.widthPct}% @${box.frame}`]);
293
+ if (run.scaleX !== 1 || ![400, 700].includes(run.weight) || !pairFiles.includes(path.basename(String(run.font)))) hangulErrors.push(["MO-A-33", `Hangul run "${run.text}" synthesized (scaleX ${run.scaleX}, weight ${run.weight}, font ${run.font}) @${box.frame}`]);
294
+ }
295
+ }
296
+ if (box.outline || box.halo) outlineErrors.push(`"${box.text}" is ${box.outline ? "outlined" : "haloed"} @${box.frame}`);
297
+ if ((box.lineCount ?? 1) >= 2) {
298
+ const cjk = (box.runs ?? []).some((run) => run.script === "hangul");
299
+ const floor = Math.max(cjk ? limits.lineHeightCjk : limits.lineHeightLatin, box.lineCount >= 3 ? limits.lineHeightThreePlus : 0);
300
+ if (!(box.lineHeight >= floor - eps)) leadingErrors.push(`"${box.elementId}" ${box.lineCount} lines at line-height ${box.lineHeight} < ${floor} @${box.frame}`);
301
+ if (Array.isArray(box.lines) && cjk) {
302
+ const shot = shotOfFrame(box.frame);
303
+ const tokens = new Set(eojeols(shot.text.replace(/\n/gu, " ")));
304
+ const bad = box.lines.flatMap((line) => eojeols(line)).find((token) => !tokens.has(token));
305
+ if (bad) breakErrors.push(`"${bad}" in ${box.elementId} @${box.frame} is not a whole 어절 of the shot text`);
306
+ }
307
+ }
308
+ if (box.role === "paragraph") {
309
+ const cjk = (box.runs ?? []).some((run) => run.script === "hangul");
310
+ if (cjk && (box.measureCh < limits.cjkMeasureMinCh || box.measureCh > limits.cjkMeasureMaxCh)) measureNotes.push(`advisory: Korean paragraph measure ${box.measureCh}ch outside ${limits.cjkMeasureMinCh}-${limits.cjkMeasureMaxCh}ch`);
311
+ if (!cjk && (box.measureCh < limits.measureMinCh || box.measureCh > limits.measureMaxCh)) measureErrors.push(`paragraph "${box.elementId}" measure ${box.measureCh}ch outside ${limits.measureMinCh}-${limits.measureMaxCh}ch @${box.frame}`);
312
+ }
313
+ }
314
+ checks["MO-C-25"] = trackingErrors.length ? fail(trackingErrors[0]) : pass(`display >= ${limits.displayTrackingFloorEm}em, machine/body >= 0`);
315
+ for (const id of ["MO-FT-04", "MO-A-33"]) { const found = hangulErrors.find(([rule]) => rule === id); checks[id] = found ? fail(found[1]) : pass(); }
316
+ checks["MO-A-35"] = outlineErrors.length ? fail(outlineErrors[0]) : pass("no outlined or haloed type");
317
+ checks["MO-C-26"] = leadingErrors.length ? fail(leadingErrors[0]) : pass(`${new Set(boxes.filter((b) => (b.lineCount ?? 1) >= 2).map((b) => b.elementId)).size} multi-line blocks at or above their floor`);
318
+ checks["MO-C-27"] = measureErrors.length ? fail(measureErrors[0]) : pass(measureNotes[0] ?? "paragraph cards inside 60-75ch");
319
+ Object.assign(checks, timelineChecks(manifest));
320
+ if (breakErrors.length) checks["MO-A-13"] = fail(breakErrors[0]);
321
+
322
+ // MO-C-06 contrast on the recorded sample frames
323
+ let minContrast = null;
324
+ const contrastErrors = [];
325
+ const crtRange = (manifest.passRanges ?? []).find((range) => range.pass === "crt");
326
+ const crtCurvature = crtRange ? crtRange.params?.curvature ?? presets.terminalcore.params.crt.curvature : 0;
327
+ for (const sample of run.samples?.frames ?? []) {
328
+ const frameFile = path.join(run.root, ".run", "samples", `f${sample.frame}.png`);
329
+ const maskFile = path.join(run.root, ".run", "samples", `f${sample.frame}-mask.png`);
330
+ const line = frameByIndex.get(sample.frame);
331
+ if (!line || !existsSync(frameFile) || !existsSync(maskFile)) { contrastErrors.push(`sample frame ${sample.frame} is missing its PNG or mask`); continue; }
332
+ const image = decodePng(readFileSync(frameFile));
333
+ const maskImage = decodePng(readFileSync(maskFile));
334
+ const mask = warpMask(maskImage.pixels, maskImage.width, maskImage.height, crtCurvature);
335
+ for (const box of line.textBoxes ?? []) {
336
+ const measured = boxContrast(image.pixels, mask, image.width, image.height, box, manifest.scale ?? 1);
337
+ if (!measured) continue;
338
+ if (!minContrast || measured.ratio / measured.floor < minContrast.ratio / minContrast.floor) minContrast = { ...measured, frame: sample.frame, text: box.text };
339
+ if (measured.ratio < measured.floor) contrastErrors.push(`"${box.text.replace(/\n/gu, " / ")}" at frame ${sample.frame}: ${measured.ratio.toFixed(2)}:1 < ${measured.floor}:1`);
340
+ }
341
+ }
342
+ checks["MO-C-06"] = !run.samples ? fail("no contrast sample frames were recorded")
343
+ : contrastErrors.length ? fail(contrastErrors[0])
344
+ : minContrast ? pass(`min ratio ${minContrast.ratio.toFixed(1)}:1 at frame ${minContrast.frame} (floor ${minContrast.floor.toFixed(1)}:1)`) : fail("no measurable text on the sample frames");
345
+
346
+ // MO-C-09 / MO-A-24 / MO-A-25 / MO-A-28
347
+ const det = run.determinism;
348
+ if (!det) checks["MO-C-09"] = fail("no determinism re-render was recorded");
349
+ else {
350
+ const mismatches = det.frames.filter((entry) => entry.master !== entry.rerender);
351
+ const logMismatch = det.frames.find((entry) => frameByIndex.get(entry.frame)?.rgbaSha256 !== entry.master);
352
+ const frames = det.frames.map((entry) => entry.frame).join(",");
353
+ if (logMismatch) checks["MO-C-09"] = fail(`recorded master hash for frame ${logMismatch.frame} does not match render.jsonl`);
354
+ else if (!mismatches.length) checks["MO-C-09"] = pass(`rgbaSha256 match Y (frames re-rendered: ${frames})`);
355
+ else if (det.swiftshader && det.swiftshader.every((entry) => entry.a === entry.b)) {
356
+ checks["MO-C-09"] = pass(`rgbaSha256 match N on hardware, Y under SwiftShader — WARN hardware-nondeterminism (frames re-rendered: ${frames})`);
357
+ warnings.push("hardware-nondeterminism");
358
+ } else checks["MO-C-09"] = fail(`rgbaSha256 match N at frame ${mismatches[0].frame}: ${mismatches[0].master} vs ${mismatches[0].rerender}${det.swiftshader ? " (SwiftShader pair also differs)" : ""}`);
359
+ }
360
+ checks["MO-A-25"] = det && det.seeked && checks["MO-C-09"].pass ? pass(`seeked re-render equals the sequential frame lines${det.statefulFrames?.length ? ` (stateful preroll frames ${det.statefulFrames.join(",")})` : ""}`) : fail(det ? "seeked frames did not match the sequential render" : "no seeked re-render recorded");
361
+ const badSample = frameLines.find((line) => !sampleTimesOk(line, manifest));
362
+ checks["MO-A-28"] = badSample ? fail(`frame ${badSample.frame} sample times do not follow t_n + (shutter/fps)((i+0.5)/N - 0.5)`) : pass(`${manifest.samples} pinned sub-samples, shutter ${manifest.shutter}`);
363
+
364
+ // MO-C-10..13, MO-A-03, MO-A-37..41, MO-C-14
365
+ const film = locateExport(run.root, "film.mp4");
366
+ const video = film ? probeVideo(film) : null;
367
+ const rate = video?.r_frame_rate ? Number(video.r_frame_rate.split("/")[0]) / Number(video.r_frame_rate.split("/")[1] ?? 1) : 0;
368
+ const tags = video && video.pix_fmt === "yuv420p" && video.color_space === "bt709" && video.color_range === "tv";
369
+ const techOk = video && !video.error && video.codec_name === "h264" && video.width >= FRAME.width && video.height >= FRAME.height && rate >= limits.minFps && Math.abs(rate - fps) < 0.01 && manifest.durationSec >= limits.minDurationSec && tags;
370
+ if (manifest.durationSec > limits.warnDurationSec) warnings.push(`duration ${manifest.durationSec}s is over ${limits.warnDurationSec}s`);
371
+ checks["MO-C-10/11/12"] = techOk ? pass(`(ffprobe yuv420p/bt709/tv Y) ${video.width}x${video.height} @ ${rate} fps, ${manifest.durationSec}s; transfer ${video.color_transfer ?? "unset"}, primaries ${video.color_primaries ?? "unset"}`)
372
+ : fail(`(ffprobe yuv420p/bt709/tv ${tags ? "Y" : "N"}) ${video ? JSON.stringify({ codec: video.codec_name, width: video.width, height: video.height, rate, pix: video.pix_fmt, space: video.color_space, range: video.color_range, trc: video.color_transfer, primaries: video.color_primaries, error: video.error }) : "no MP4"}; duration ${manifest.durationSec}s`);
373
+ checks["MO-A-03"] = techOk ? pass("pinned BT.709 encode") : fail("MP4 encode tags do not match the pinned BT.709 encode");
374
+ const previewFile = locateExport(run.root, "preview.webp") ?? locateExport(run.root, "preview.gif");
375
+ const poster = locateExport(run.root, "poster.png");
376
+ const still = locateExport(run.root, "reduced-motion.png");
377
+ const sizes = { mp4: film ? statSync(film).size : 0, preview: previewFile ? statSync(previewFile).size : 0, poster: poster ? statSync(poster).size : 0 };
378
+ if (film && sizes.mp4 > limits.mp4WarnBytesPer10s * (manifest.durationSec / 10)) warnings.push(`MP4 is ${sizes.mp4} B, over 100 MB per 10 s`);
379
+ const sizeOk = sizes.preview > 0 && sizes.preview <= limits.previewMaxBytes && sizes.poster > 0 && sizes.poster <= limits.posterMaxBytes;
380
+ checks["MO-C-13"] = sizeOk ? pass(`mp4 ${sizes.mp4}, ${previewFile ? path.basename(previewFile).split(".").pop() : "webp"} ${sizes.preview} (cap 3 MB), poster ${sizes.poster} (cap 1 MB)`)
381
+ : fail(`mp4 ${sizes.mp4}, preview ${sizes.preview} (cap 3 MB), poster ${sizes.poster} (cap 1 MB)`);
382
+ const missing = [["MP4", film], ["preview", previewFile], ["poster", poster], ["reduced-motion still", still]].filter(([, file]) => !file).map(([name]) => name);
383
+ checks["MO-A-37-41"] = missing.length ? fail(`missing ${missing.join(", ")}`) : pass("MP4, preview, poster, reduced-motion still and manifest present");
384
+ const lastText = [...timeline].filter(isShot).at(-1);
385
+ const referenceFrame = lastText ? Math.round(lastText.end * fps) - 1 : frameCount - 1;
386
+ const referenceInk = frameByIndex.get(referenceFrame)?.inkPixels ?? 0;
387
+ const stillInk = run.still?.inkPixels ?? 0;
388
+ checks["MO-C-14"] = still && referenceInk > 0 && stillInk >= limits.stillInkRatio * referenceInk ? pass(`present Y, ink-coverage check PASS (${stillInk} vs ${referenceInk} at frame ${referenceFrame})`)
389
+ : fail(`present ${still ? "Y" : "N"}, ink-coverage check FAIL (${stillInk} vs ${referenceInk} at frame ${referenceFrame}, need ${limits.stillInkRatio}x)`);
390
+
391
+ // MO-C-29 one signal + one accent cluster
392
+ const observations = [];
393
+ for (const line of frameLines) {
394
+ const shot = shotOfFrame(line.frame);
395
+ for (const box of line.textBoxes ?? []) if (typeof box.fill === "string" && bigEnough(box.bbox)) observations.push({ color: box.fill, frame: line.frame, entryId: shot.id });
396
+ for (const fill of line.fills ?? []) {
397
+ if (!bigEnough(fill.bbox)) continue;
398
+ for (const color of fill.stops ?? [fill.color]) observations.push({ color, frame: line.frame, entryId: shot.id });
399
+ }
400
+ }
401
+ const clusters = hueClusters(observations).sort((a, b) => b.frames - a.frames);
402
+ const accentHex = look.palette.accent?.toUpperCase();
403
+ const accent = clusters.find((c) => accentHex && c.colors.includes(accentHex)) ?? (clusters.length > 1 ? clusters.at(-1) : null);
404
+ checks["MO-C-29"] = clusters.length > 2 ? fail(`${clusters.length} saturated clusters: ${clusters.map((c) => `${c.hue}° ${c.colors.join("/")}`).join(", ")}`)
405
+ : accent && accent.entries.length > limits.accentMaxEntries ? fail(`accent ${accent.colors.join("/")} appears in ${accent.entries.length} timeline entries: ${accent.entries.join(", ")}`)
406
+ : accent && accent.frames > limits.accentMaxFrameFraction * frameCount ? fail(`accent ${accent.colors.join("/")} on ${accent.frames}/${frameCount} frames (> ${limits.accentMaxFrameFraction * 100}%)`)
407
+ : pass(`${clusters.length} saturated cluster(s)${accent ? `; accent in ${accent.entries.join(", ")} on ${accent.frames} frames` : ""}`);
408
+
409
+ // MO-D-02..04
410
+ const perf = run.perf;
411
+ if (!perf) checks["MO-D-02"] = fail("no perf run recorded");
412
+ else {
413
+ const times = [...perf.frameTimeMs].sort((a, b) => a - b);
414
+ const p95 = times[Math.max(0, Math.ceil(times.length * 0.95) - 1)];
415
+ const ceiling = isSoftwareRenderer(perf.renderer) ? limits.softwareGpuP95Ms : limits.realGpuP95Ms;
416
+ checks["MO-D-02"] = times.length >= limits.perfFrames && p95 <= ceiling ? pass(`p95 ${p95.toFixed(1)} ms over ${times.length} frames (ceiling ${ceiling} ms)`)
417
+ : fail(`p95 ${p95?.toFixed(1)} ms over ${times.length} frames (ceiling ${ceiling} ms); lower --samples or tidal octaves`);
418
+ }
419
+ let emptyError = null;
420
+ for (const shot of shots) {
421
+ const first = Math.round(shot.start * fps), last = Math.round(shot.end * fps) - 1;
422
+ const allowance = Math.round(limits.nearBlackFloorMultiple * limits.minSceneBeats * beat * fps);
423
+ let run0 = 0;
424
+ for (let frame = first; frame <= last; frame++) {
425
+ const line = frameByIndex.get(frame);
426
+ const empty = line && line.inkPixels === 0 && line.p995L < limits.nearBlackLuminance;
427
+ run0 = empty ? run0 + 1 : 0;
428
+ const edge = frame < limits.nearBlackFadeSec * fps || frame >= frameCount - limits.nearBlackFadeSec * fps ? limits.nearBlackFadeSec * fps : 0;
429
+ if (run0 > allowance + edge) { emptyError = `${run0} empty/near-black frames ending at ${frame} in ${shot.id} (allowance ${allowance})`; break; }
430
+ }
431
+ if (emptyError) break;
432
+ }
433
+ checks["MO-D-03"] = emptyError ? fail(emptyError) : pass("no empty or near-black run past 2x the scene's minimum hold");
434
+ const glyphs = run.preflight?.missingGlyphs;
435
+ checks["MO-D-04"] = !run.preflight ? fail("pre-flight glyph coverage was not recorded") : glyphs.length ? fail(`missing glyphs: ${glyphs.slice(0, 5).join(", ")}`) : pass("every codepoint resolves in its assigned font");
436
+
437
+ // MO-B-00 recheck, MO-C-15/16 round bookkeeping
438
+ if (run.brief) {
439
+ const expected = selectPreset(run.brief.sourceText ?? "", run.brief.explicitPreset);
440
+ checks["MO-B-00"] = expected.id === manifest.presetId ? pass(`${manifest.presetId} (${expected.reason})`) : fail(`preset ${manifest.presetId} but the keyword table picks ${expected.id}`);
441
+ } else checks["MO-B-00"] = fail("no brief copy recorded");
442
+ const round = manifest.craftRound;
443
+ checks["MO-C-15/16"] = Number.isInteger(round) && round >= 1 && round <= 3 ? pass(`round ${round} of 3`) : fail(`craft round ${round} outside 1..3`);
444
+
445
+ // Sound rows on the decoded muxed stream, for renders that planned sound through a treatment.
446
+ if (manifest.sound?.mode) {
447
+ for (const [id, row] of Object.entries(soundChecks(film, manifest.durationSec, manifest.sound.mode))) {
448
+ if (row.warn) warnings.push(`${id}: ${row.detail}`);
449
+ else checks[id] = row;
450
+ }
451
+ }
452
+ const failed = Object.entries(checks).filter(([, check]) => !check.pass).map(([id]) => id);
453
+ return { run, manifest, checks, warnings, failed, passed: failed.length === 0, sizes, minContrast, frameCount, flash: { master, preview } };
454
+ }
455
+
456
+ const fixedOrder = ["MO-C-25", "MO-C-26", "MO-C-27", "MO-C-29", "MO-D-02", "MO-D-03", "MO-D-04"];
457
+ const indexOrder = ["MO-A-03", "MO-A-04", "MO-A-05", "MO-A-13", "MO-A-15", "MO-A-16", "MO-A-25", "MO-A-28", "MO-A-33", "MO-A-35", "MO-A-37-41", "MO-A-41a", "MO-A-51", "MO-A-58",
458
+ "MO-SH-01", "MO-SH-03", "MO-SH-04a", "MO-SH-05", "MO-SH-06", "MO-SH-07", "MO-SH-08", "MO-SH-09", "MO-SH-10", "MO-B-00", "MO-FT-04", "MO-C-15/16"];
459
+ const labels = {
460
+ "MO-C-01": "GLSL presence: ", "MO-C-02": "WebGL2 tier: ", "MO-C-03": "flash audit: ", "MO-C-04": "title-safe: ",
461
+ "MO-C-05": "action-safe: ", "MO-C-06": "type contrast: ", "MO-C-07/08": "reading time: ", "MO-C-09": "determinism: ",
462
+ "MO-C-10/11/12": "duration/fps/res: ", "MO-C-13": "file sizes: ", "MO-C-14": "reduced-motion still: "
463
+ };
464
+
465
+ export function formatReport(result, context) {
466
+ const { manifest, checks } = result;
467
+ const out = (name) => path.join(context.exportDir, name);
468
+ const previewName = manifest.previewEncoder === "gif" ? "preview.gif" : "preview.webp";
469
+ const lines = [
470
+ "lit-typographic-motion — render report",
471
+ `outputs: ${out("film.mp4")} · ${out(previewName)} (encoder: ${manifest.previewEncoder}) · ${out("poster.png")} · ${out("reduced-motion.png")}`,
472
+ `preset: ${manifest.presetId} (chosen because: ${context.presetReason})`,
473
+ `duration / fps / resolution: ${manifest.durationSec} s @ ${manifest.fps} fps, ${manifest.resolution[0] * (manifest.scale ?? 1)}x${manifest.resolution[1] * (manifest.scale ?? 1)}`,
474
+ `GLSL passes (manifest): ${(manifest.passRanges ?? []).map((r) => `${r.pass}@${r.sceneId}#${r.shotIndex}:${r.frameStart}-${r.frameEnd}`).join(", ")}`,
475
+ `WebGL2: ${manifest.softwareRenderer ? "software" : "hardware"} — ${manifest.renderer} (flags: ${(manifest.chromeFlags ?? []).join(" ")})`,
476
+ "",
477
+ `QA gate: ${result.passed ? "PASS" : "FAIL"}`
478
+ ];
479
+ const line = (id) => {
480
+ const check = checks[id];
481
+ const provisional = id === "MO-C-07/08" || provisionalRules.includes(id) ? " [provisional]" : "";
482
+ const status = check.pass ? "PASS" : "FAIL";
483
+ if (id === "MO-C-03") return ` MO-C-03 flash audit: ${check.detail.split(";")[0]} ${status}`;
484
+ if (id === "MO-C-06") return ` MO-C-06 type contrast: ${check.detail} ${status}${provisional}`;
485
+ if (id === "MO-C-07/08") return ` MO-C-07/08 reading time: ${check.detail} ${status}${provisional}`;
486
+ if (id === "MO-C-09") return ` MO-C-09 determinism: ${check.detail} ${status}`;
487
+ if (id === "MO-C-10/11/12") return ` MO-C-10/11/12 duration/fps/res: ${status} ${check.detail}`;
488
+ if (id === "MO-C-13") return ` MO-C-13 file sizes: ${check.detail} ${status}${provisional}`;
489
+ if (id === "MO-C-14") return ` MO-C-14 reduced-motion still: ${check.detail}${provisional}`;
490
+ return ` ${id} ${labels[id] ?? ""}${status}${check.detail ? ` (${check.detail})` : ""}${provisional}`;
491
+ };
492
+ for (const id of ["MO-C-01", "MO-C-02", "MO-C-03", "MO-C-04", "MO-C-05", "MO-C-06", "MO-C-07/08", "MO-C-09", "MO-C-10/11/12", "MO-C-13", "MO-C-14"]) lines.push(line(id));
493
+ for (const id of fixedOrder) lines.push(line(id));
494
+ for (const id of indexOrder) if (checks[id]) lines.push(line(id));
495
+ for (const id of Object.keys(checks).filter((key) => key.startsWith("SOUND"))) lines.push(line(id));
496
+ lines.push("", `craft rounds run: ${manifest.craftRound} / 3 max`, `frames actually viewed this run: ${context.viewed} (confirmed looked, not just rendered)`);
497
+ if (!checks["MO-C-03"].pass) lines.push(`MO-C-03 worst window: ${checks["MO-C-03"].detail}`);
498
+ if (result.warnings.length) lines.push(`warnings: ${result.warnings.join("; ")}`);
499
+ lines.push(`provisional thresholds (no user sign-off recorded): ${provisionalRules.join(", ")}`);
500
+ lines.push(`gate exit: ${context.exitCode}`);
501
+ lines.push(`export state: ${context.exportState}`);
502
+ lines.push(`brief: ${context.briefPath ?? "unknown"}`);
503
+ return lines.join("\n") + "\n";
504
+ }
505
+
506
+ // Promote or withhold (MO-C-16): a surviving MO-C-03 FAIL puts every export only in withheld/;
507
+ // otherwise exports move to their deliverable names, including after other FAILs (MO-A-45).
508
+ export function applyExports(root, flashPass) {
509
+ const withheld = path.join(root, "withheld");
510
+ for (const name of exportNames) {
511
+ const sources = [path.join(root, ".run", name), path.join(root, name), path.join(withheld, name)].filter(existsSync);
512
+ const source = sources[0];
513
+ if (!source) continue;
514
+ const target = flashPass ? path.join(root, name) : path.join(withheld, name);
515
+ if (!flashPass) mkdirSync(withheld, { recursive: true });
516
+ if (source !== target) renameSync(source, target);
517
+ for (const extra of sources.slice(1)) if (extra !== target && existsSync(extra)) rmSync(extra);
518
+ }
519
+ if (flashPass && existsSync(withheld) && readdirSync(withheld).length === 0) rmSync(withheld, { recursive: true });
520
+ return flashPass ? "delivered" : "withheld";
521
+ }
522
+
523
+ // Frames viewed this round: the look round recorded on this render when there is one; otherwise the
524
+ // --viewed count, which a re-run without --viewed keeps for the same craft round.
525
+ function viewedCount(root, round, viewed) {
526
+ const lookFile = path.join(root, "look.json");
527
+ if (existsSync(lookFile)) {
528
+ const look = JSON.parse(readFileSync(lookFile, "utf8"));
529
+ const recorded = look.rounds?.filter((entry) => entry.round === round).at(-1);
530
+ if (recorded) return Object.keys(recorded.frames ?? {}).length;
531
+ }
532
+ const viewedFile = path.join(root, ".run", "viewed.json");
533
+ if (viewed === undefined) {
534
+ try { const prior = JSON.parse(readFileSync(viewedFile, "utf8")); return prior.round === round ? prior.count : 0; } catch { return 0; }
535
+ }
536
+ if (existsSync(path.dirname(viewedFile))) writeFileSync(viewedFile, JSON.stringify({ round, count: viewed }) + "\n");
537
+ return viewed;
538
+ }
539
+
540
+ export function runGate(dir, { viewed, requirePreview = true } = {}) {
541
+ const root = path.resolve(dir);
542
+ const manifestPath = JSON.parse(readFileSync(path.join(root, "manifest.json"), "utf8")).path;
543
+ if (manifestPath === "stage") return runStageGate(root, { viewed });
544
+ const result = checkRun(root, { requirePreview });
545
+ viewed = viewedCount(root, result.manifest?.craftRound ?? null, viewed);
546
+ const flashPass = result.checks["MO-C-03"].pass;
547
+ const exportState = applyExports(root, flashPass);
548
+ const exitCode = result.passed ? EXIT.OK : EXIT.GATE_FAIL_QA;
549
+ const presetReason = result.run.brief?.explicitPreset ? (result.run.brief.presetSource === "user" ? "user-specified" : "agent default") : selectPreset(result.run.brief?.sourceText ?? "", undefined).reason;
550
+ const report = formatReport(result, { exportDir: flashPass ? root : path.join(root, "withheld"), viewed, exitCode, exportState: exportState === "withheld" ? "withheld (MO-C-03 FAIL: diagnostics only, never deliverables)" : exportState, presetReason, briefPath: result.run.brief?.path });
551
+ writeFileSync(path.join(root, "gate-report.txt"), report);
552
+ return { ...result, exitCode, report, exportState };
553
+ }
554
+
555
+ function runStageGate(root, { viewed }) {
556
+ const result = checkStageRun(root);
557
+ viewed = viewedCount(root, result.manifest.craftRound, viewed);
558
+ const flashPass = result.checks["MO-C-03"].pass;
559
+ const exportState = applyExports(root, flashPass);
560
+ const exitCode = result.passed ? EXIT.OK : EXIT.GATE_FAIL_QA;
561
+ const report = formatStageReport(result, { exportDir: flashPass ? root : path.join(root, "withheld"), viewed, exitCode, exportState: exportState === "withheld" ? "withheld (MO-C-03 FAIL: diagnostics only, never deliverables)" : exportState });
562
+ writeFileSync(path.join(root, "gate-report.txt"), report);
563
+ return { ...result, exitCode, report, exportState };
564
+ }
565
+
566
+ // A turn counts as done only after a gate PASS, a valid treatment and two recorded look rounds, the
567
+ // last one on the final render's own stills (engine/look.mjs).
568
+ export function completionState(dir) {
569
+ return doneState(dir);
570
+ }
571
+
572
+ function main(argv) {
573
+ if (!argv.length || argv.includes("--help")) {
574
+ console.log("lit-typographic-motion gate\nUsage: node gate.mjs <output-dir> [--viewed N]\n node gate.mjs --done <output-dir> (0 DONE, 1 NOT DONE, 2 DONE_WITH_OPEN_ITEMS after round 3, 3 DONE_UNVIEWED)");
575
+ return 0;
576
+ }
577
+ if (argv[0] === "--done") {
578
+ const state = completionState(argv[1]);
579
+ console.log(formatDone(state));
580
+ return state.code;
581
+ }
582
+ const viewedIndex = argv.indexOf("--viewed");
583
+ const viewed = viewedIndex >= 0 ? Number(argv[viewedIndex + 1]) || 0 : undefined;
584
+ const result = runGate(argv[0], { viewed });
585
+ process.stdout.write(result.report);
586
+ return result.exitCode;
587
+ }
588
+
589
+ if (process.argv[1] && existsSync(process.argv[1]) && realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url))) {
590
+ try { process.exitCode = main(process.argv.slice(2)); }
591
+ catch (error) { console.error(`gate error: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = EXIT.GATE_FAIL_QA; }
592
+ }
593
+