streamtex 0.7.78__tar.gz → 0.7.80__tar.gz

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 (197) hide show
  1. {streamtex-0.7.78/streamtex.egg-info → streamtex-0.7.80}/PKG-INFO +2 -1
  2. {streamtex-0.7.78 → streamtex-0.7.80}/pyproject.toml +2 -1
  3. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/__init__.py +17 -0
  4. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/bib.py +38 -18
  5. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/book.py +77 -15
  6. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/claude_cmd.py +13 -0
  7. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/claude_project.py +8 -1
  8. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/commands.py +2 -0
  9. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/export_cmd.py +3 -0
  10. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/release_cmd.py +12 -0
  11. streamtex-0.7.80/streamtex/cli/styles_cmd.py +360 -0
  12. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/deploy/stx_auth.py +1 -1
  13. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/export_enrich.py +28 -2
  14. streamtex-0.7.80/streamtex/glossary.py +261 -0
  15. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/target.py +32 -6
  16. streamtex-0.7.80/streamtex/stage.py +183 -0
  17. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/static/default.css +49 -0
  18. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/utils.py +7 -2
  19. {streamtex-0.7.78 → streamtex-0.7.80/streamtex.egg-info}/PKG-INFO +2 -1
  20. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex.egg-info/SOURCES.txt +3 -0
  21. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex.egg-info/requires.txt +1 -0
  22. {streamtex-0.7.78 → streamtex-0.7.80}/LICENSE +0 -0
  23. {streamtex-0.7.78 → streamtex-0.7.80}/MANIFEST.in +0 -0
  24. {streamtex-0.7.78 → streamtex-0.7.80}/README.md +0 -0
  25. {streamtex-0.7.78 → streamtex-0.7.80}/setup.cfg +0 -0
  26. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/__main__.py +0 -0
  27. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/ai/__init__.py +0 -0
  28. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/ai/config.py +0 -0
  29. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/ai/generate.py +0 -0
  30. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/ai/history.py +0 -0
  31. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/ai/metadata.py +0 -0
  32. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/ai/providers/__init__.py +0 -0
  33. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/ai/providers/base.py +0 -0
  34. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/ai/providers/fal.py +0 -0
  35. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/ai/providers/google.py +0 -0
  36. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/ai/providers/openai.py +0 -0
  37. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/ai/providers/registry.py +0 -0
  38. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/auth.py +0 -0
  39. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/banner.py +0 -0
  40. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/bib_preview.py +0 -0
  41. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/block_helpers.py +0 -0
  42. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/blocks.py +0 -0
  43. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/browser.py +0 -0
  44. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/__init__.py +0 -0
  45. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/_claude_files.py +0 -0
  46. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/_divergence.py +0 -0
  47. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/_install_local_packs.py +0 -0
  48. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/_shared.py +0 -0
  49. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/_stx_toml.py +0 -0
  50. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/_toml_helpers.py +0 -0
  51. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/artifact_cmd.py +0 -0
  52. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/bib_cmd.py +0 -0
  53. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/build_check.py +0 -0
  54. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/cache_cmd.py +0 -0
  55. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/claude_global.py +0 -0
  56. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/component_cmd.py +0 -0
  57. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/console.py +0 -0
  58. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/coolify.py +0 -0
  59. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/deploy_auth_cmd.py +0 -0
  60. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/deploy_cmd.py +0 -0
  61. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/dev_cmd.py +0 -0
  62. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/dev_config.py +0 -0
  63. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/ds_cmd.py +0 -0
  64. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/install_cmd.py +0 -0
  65. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/kit_cmd.py +0 -0
  66. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/main.py +0 -0
  67. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/migrations/__init__.py +0 -0
  68. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/migrations/base.py +0 -0
  69. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/migrations/compat.py +0 -0
  70. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/migrations/registry.py +0 -0
  71. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/migrations/v0_4_0.py +0 -0
  72. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/migrations/v0_4_6.py +0 -0
  73. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/pack_cmd.py +0 -0
  74. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/project_cmd.py +0 -0
  75. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/project_rules.py +0 -0
  76. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/publish_cmd.py +0 -0
  77. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/published_check.py +0 -0
  78. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/run_cmd.py +0 -0
  79. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/run_set.py +0 -0
  80. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/screenshot_cmd.py +0 -0
  81. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/shortcuts.py +0 -0
  82. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/status_cmd.py +0 -0
  83. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/sync_cmd.py +0 -0
  84. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/upgrade_cmd.py +0 -0
  85. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/validate_cmd.py +0 -0
  86. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/cli/workspace_cmd.py +0 -0
  87. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/code.py +0 -0
  88. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/collection.py +0 -0
  89. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/constants.py +0 -0
  90. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/container.py +0 -0
  91. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/__init__.py +0 -0
  92. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/artifacts/__init__.py +0 -0
  93. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/artifacts/_frontmatter.py +0 -0
  94. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/artifacts/agent.py +0 -0
  95. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/artifacts/ai_prompt.py +0 -0
  96. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/artifacts/archetype.py +0 -0
  97. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/artifacts/asset.py +0 -0
  98. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/artifacts/discovery.py +0 -0
  99. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/artifacts/guideline.py +0 -0
  100. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/artifacts/install.py +0 -0
  101. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/artifacts/integration.py +0 -0
  102. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/artifacts/loaders.py +0 -0
  103. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/artifacts/palette.py +0 -0
  104. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/artifacts/skill.py +0 -0
  105. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/artifacts/spec.py +0 -0
  106. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/artifacts/validation.py +0 -0
  107. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/contracts.py +0 -0
  108. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/discovery.py +0 -0
  109. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/core/validation.py +0 -0
  110. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/countdown.py +0 -0
  111. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/deeplink.py +0 -0
  112. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/deploy/__init__.py +0 -0
  113. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/enums.py +0 -0
  114. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/export.py +0 -0
  115. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/export_paginate.py +0 -0
  116. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/export_widgets.py +0 -0
  117. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/facts.py +0 -0
  118. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/grid.py +0 -0
  119. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/gsheet.py +0 -0
  120. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/hover_tooltip.py +0 -0
  121. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/i18n.py +0 -0
  122. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/image.py +0 -0
  123. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/image_crop.py +0 -0
  124. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/image_editor.py +0 -0
  125. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/image_utils.py +0 -0
  126. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/inspector.py +0 -0
  127. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/kept.py +0 -0
  128. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/latex.py +0 -0
  129. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/latex_utils.py +0 -0
  130. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/link_config.py +0 -0
  131. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/link_preview.py +0 -0
  132. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/list.py +0 -0
  133. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/loading.py +0 -0
  134. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/markdown.py +0 -0
  135. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/marker.py +0 -0
  136. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/marker_runtime.py +0 -0
  137. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/media_overlay.py +0 -0
  138. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/mermaid.py +0 -0
  139. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/overlay.py +0 -0
  140. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/pagewalk.py +0 -0
  141. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/pdf_export.py +0 -0
  142. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/plantuml.py +0 -0
  143. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/presentation.py +0 -0
  144. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/presentation_profile.py +0 -0
  145. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/printing.py +0 -0
  146. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/__init__.py +0 -0
  147. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/build.py +0 -0
  148. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/config.py +0 -0
  149. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/coolify.py +0 -0
  150. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/levels.py +0 -0
  151. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/media.py +0 -0
  152. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/ops.py +0 -0
  153. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/passwords.py +0 -0
  154. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/state.py +0 -0
  155. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/templates/live/Dockerfile +0 -0
  156. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/templates/live/entrypoint.sh +0 -0
  157. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/templates/live/nginx.conf +0 -0
  158. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/templates/live/stx-http.conf +0 -0
  159. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/templates/live/supervisord.conf +0 -0
  160. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/templates/static/10-stx-init.sh +0 -0
  161. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/templates/static/20-stx-auth.sh +0 -0
  162. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/templates/static/Dockerfile +0 -0
  163. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/templates/static/closed.html +0 -0
  164. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/templates/static/nginx.conf +0 -0
  165. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/templates/static/stx-http.conf +0 -0
  166. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/release/templates/static/stx_auth.py +0 -0
  167. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/runtime_flags.py +0 -0
  168. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/scripts/__init__.py +0 -0
  169. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/scripts/migrate_curves_to_relative.py +0 -0
  170. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/search.py +0 -0
  171. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/slide.py +0 -0
  172. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/slide_note.py +0 -0
  173. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/space.py +0 -0
  174. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/spacing.py +0 -0
  175. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/static/css/stx_global.css +0 -0
  176. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/static/js/stx_countdown.js +0 -0
  177. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/static/js/stx_marker_observer.js +0 -0
  178. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/static/js/stx_scroll_spy.js +0 -0
  179. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/static/js/stx_video.js +0 -0
  180. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/static/logo-stx-tiny.png +0 -0
  181. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/static/logo-stx.png +0 -0
  182. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/styles/__init__.py +0 -0
  183. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/styles/base.py +0 -0
  184. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/styles/container.py +0 -0
  185. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/styles/core.py +0 -0
  186. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/styles/scale.py +0 -0
  187. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/styles/scale_curves.toml +0 -0
  188. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/styles/text.py +0 -0
  189. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/styles/visibility.py +0 -0
  190. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/tikz.py +0 -0
  191. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/toc.py +0 -0
  192. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/watch.py +0 -0
  193. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/write.py +0 -0
  194. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex/zoom.py +0 -0
  195. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex.egg-info/dependency_links.txt +0 -0
  196. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex.egg-info/entry_points.txt +0 -0
  197. {streamtex-0.7.78 → streamtex-0.7.80}/streamtex.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: streamtex
3
- Version: 0.7.78
3
+ Version: 0.7.80
4
4
  Summary: AI-powered content framework for Streamlit — create presentations, courses, and web-books with Claude or Cursor, no coding required.
5
5
  Author-email: Nicolas Guelfi <nicolas.guelfi@laposte.net>
6
6
  License-Expression: BUSL-1.1
@@ -38,6 +38,7 @@ Requires-Dist: streamlit-mermaid>=0.3.0
38
38
  Requires-Dist: mermaid-py>=0.5.0
39
39
  Requires-Dist: python-dotenv>=1.2.1
40
40
  Requires-Dist: Pillow>=10.0
41
+ Requires-Dist: pyyaml>=6.0
41
42
  Provides-Extra: inspector
42
43
  Requires-Dist: streamlit-ace>=0.1.1; extra == "inspector"
43
44
  Provides-Extra: cli
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "streamtex"
7
- version = "0.7.78"
7
+ version = "0.7.80"
8
8
  description = "AI-powered content framework for Streamlit — create presentations, courses, and web-books with Claude or Cursor, no coding required."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -43,6 +43,7 @@ dependencies = [
43
43
  "mermaid-py>=0.5.0",
44
44
  "python-dotenv>=1.2.1",
45
45
  "Pillow>=10.0",
46
+ "pyyaml>=6.0",
46
47
  ]
47
48
 
48
49
  [project.scripts]
@@ -178,6 +178,14 @@ try:
178
178
  st_refs, BibRefs, generate_bib_stubs,
179
179
  )
180
180
 
181
+ # Glossary: hover definitions, CSS only (#12)
182
+ from .glossary import (
183
+ GlossaryConfig, GlossaryRegistry,
184
+ set_glossary_config, get_glossary_config,
185
+ get_glossary_registry, reset_glossary_registry,
186
+ load_glossary, gloss, st_glossary,
187
+ )
188
+
181
189
  # Link behavior configuration
182
190
  from .link_config import LinkConfig, set_link_config, get_link_config
183
191
 
@@ -290,6 +298,8 @@ __all__ = [
290
298
  "ProfileConfig",
291
299
  "ProjectBlockRegistry",
292
300
  "ProjectMeta",
301
+ "GlossaryConfig",
302
+ "GlossaryRegistry",
293
303
  "ReuseArchitectureError",
294
304
  "SLIDE_CONTAINER",
295
305
  "SLIDE_NOTE_STYLE",
@@ -320,6 +330,8 @@ __all__ = [
320
330
  "exec_static",
321
331
  "export_bibtex",
322
332
  "export_pdf",
333
+ "load_glossary",
334
+ "reset_glossary_registry",
323
335
  "extract_frames",
324
336
  "extract_math",
325
337
  "extract_tikz",
@@ -329,6 +341,9 @@ __all__ = [
329
341
  "get_ai_image_config",
330
342
  "get_available_models",
331
343
  "get_bib_config",
344
+ "get_glossary_config",
345
+ "get_glossary_registry",
346
+ "gloss",
332
347
  "get_bib_registry",
333
348
  "get_block_helper_config",
334
349
  "get_block_spacing",
@@ -381,6 +396,7 @@ __all__ = [
381
396
  "save_image_version",
382
397
  "set_ai_image_config",
383
398
  "set_bib_config",
399
+ "set_glossary_config",
384
400
  "set_block_helper_config",
385
401
  "set_block_spacing",
386
402
  "set_gsheet_config",
@@ -402,6 +418,7 @@ __all__ = [
402
418
  "st_audio",
403
419
  "st_bar_chart",
404
420
  "st_bibliography",
421
+ "st_glossary",
405
422
  "st_block",
406
423
  "st_book",
407
424
  "st_br",
@@ -1065,7 +1065,9 @@ def st_bibliography(*, style=None, title: str = "References",
1065
1065
  toc_lvl: Optional[str] = None,
1066
1066
  only_cited: bool = True,
1067
1067
  format: Optional[BibFormat] = None,
1068
- label_style: Optional[CitationStyle] = None) -> None:
1068
+ label_style: Optional[CitationStyle] = None,
1069
+ chunk_size: Optional[int] = None,
1070
+ slide_break_config=None) -> None:
1069
1071
  """Render the full bibliography list.
1070
1072
 
1071
1073
  Args:
@@ -1082,9 +1084,16 @@ def st_bibliography(*, style=None, title: str = "References",
1082
1084
  shows inline: ``(Dart et al., 2013)`` in AUTHOR_YEAR, ``[3]`` in
1083
1085
  NUMERIC and SUPERSCRIPT. Pass ``CitationStyle.NUMERIC`` to keep
1084
1086
  ``[N]`` beside author-year citations.
1087
+ chunk_size: When set, at most this many entries per slide: a
1088
+ ``st_slide_break()`` separates the chunks, each repeats the title
1089
+ with its rank (``References (2/5)``) and the numbering goes on.
1090
+ The TOC gets the plain title once. ``None``: one list (#23).
1091
+ slide_break_config: The ``SlideBreakConfig`` of the breaks between
1092
+ chunks (default: the global one).
1085
1093
  """
1086
1094
  from .container import st_block
1087
1095
  from .export import _render
1096
+ from .slide import st_slide_break
1088
1097
  from .space import st_space
1089
1098
  from .styles import StxStyles
1090
1099
  from .write import st_write
@@ -1099,28 +1108,39 @@ def st_bibliography(*, style=None, title: str = "References",
1099
1108
  # Sort
1100
1109
  entries = _sort_entries(entries, cfg.sort_by)
1101
1110
 
1102
- # Title
1103
- ts = title_style or (StxStyles.big + StxStyles.bold)
1104
- if title:
1105
- st_write(ts, title, toc_lvl=toc_lvl)
1106
- st_space("v", 2)
1111
+ if chunk_size is not None and chunk_size < 1:
1112
+ raise ValueError(f"st_bibliography: chunk_size must be at least 1, not {chunk_size}")
1113
+ size = chunk_size or len(entries)
1114
+ chunks = [entries[i:i + size] for i in range(0, len(entries), size)]
1107
1115
 
1108
- # Build inline CSS from Style objects
1116
+ ts = title_style or (StxStyles.big + StxStyles.bold)
1109
1117
  entry_css = entry_style.css if entry_style else ""
1110
1118
  number_css = number_style.css if number_style else "font-weight:bold;"
1111
1119
  labels = label_style or cfg.citation_style
1112
1120
 
1113
- # Entries
1114
- with st_block(style):
1115
- for i, entry in enumerate(entries):
1116
- formatted = format_entry(entry, fmt, number=0)
1117
- num_html = f'<span style="{number_css}">{_entry_label(entry, i + 1, labels)}</span> '
1118
- anchor_id = f"bib-{entry.key}"
1119
- _render(
1120
- f'<p id="{anchor_id}" style="margin-bottom:10px;text-indent:-2.5em;'
1121
- f'padding-left:2.5em;line-height:1.6;overflow-wrap:anywhere;{entry_css}">'
1122
- f'{num_html}{formatted}</p>'
1123
- )
1121
+ first = 1
1122
+ for k, chunk in enumerate(chunks, 1):
1123
+ if k > 1:
1124
+ st_slide_break(marker_label=f"{title or 'References'} {k}/{len(chunks)}",
1125
+ config=slide_break_config)
1126
+ if title:
1127
+ rank = f" ({k}/{len(chunks)})" if len(chunks) > 1 else ""
1128
+ if k == 1:
1129
+ st_write(ts, title + rank, toc_lvl=toc_lvl, label=title if toc_lvl else "")
1130
+ else:
1131
+ st_write(ts, title + rank)
1132
+ st_space("v", 2)
1133
+ with st_block(style):
1134
+ for i, entry in enumerate(chunk, first):
1135
+ formatted = format_entry(entry, fmt, number=0)
1136
+ num_html = f'<span style="{number_css}">{_entry_label(entry, i, labels)}</span> '
1137
+ anchor_id = f"bib-{entry.key}"
1138
+ _render(
1139
+ f'<p id="{anchor_id}" style="margin-bottom:10px;text-indent:-2.5em;'
1140
+ f'padding-left:2.5em;line-height:1.6;overflow-wrap:anywhere;{entry_css}">'
1141
+ f'{num_html}{formatted}</p>'
1142
+ )
1143
+ first += len(chunk)
1124
1144
 
1125
1145
 
1126
1146
  def _entry_label(entry: BibEntry, number: int, style: CitationStyle) -> str:
@@ -85,6 +85,7 @@ from .spacing import (
85
85
  resolve_block_spacing,
86
86
  set_active_profile,
87
87
  )
88
+ from .stage import STAGE_KEY
88
89
  from .styles import Style
89
90
  from .toc import NumberingMode, TOCConfig, reset_toc_registry, toc_entries
90
91
  from .utils import inject_link_preview_scaffold
@@ -536,6 +537,7 @@ def _offer_export_downloads(html: str, base_name: str,
536
537
  doc_version=_cache.get("doc_version", ""),
537
538
  lib_version=_cache.get("lib_version", ""),
538
539
  notice=rules["notice"],
540
+ stage=st.session_state.get(STAGE_KEY),
539
541
  )
540
542
  # Apply custom title override
541
543
  if enrich_title:
@@ -726,24 +728,44 @@ def _resolve_sidebar_max_level(toc_config: TOCConfig, paginated: bool) -> int |
726
728
  return 1 if paginated else 2
727
729
 
728
730
 
729
- def _setup_bibliography(bib_sources, bib_config):
730
- """Load bibliography sources and set config (called at start of st_book)."""
731
+ def _setup_bibliography(bib_sources, bib_config, glossary_sources=None, glossary_config=None):
732
+ """Load bibliography and glossary sources and set config (called at start of st_book).
733
+
734
+ The ``@glossary`` entries of a bibliography source go to the glossary, so
735
+ they never take a citation number (#12).
736
+ """
731
737
  from .bib import get_bib_registry, load_bib, reset_bib_registry, set_bib_config
738
+ from .glossary import (
739
+ get_glossary_registry,
740
+ is_glossary,
741
+ load_glossary,
742
+ reset_glossary_registry,
743
+ set_glossary_config,
744
+ )
732
745
 
733
746
  reset_bib_registry()
747
+ reset_glossary_registry()
734
748
 
735
749
  if bib_config is not None:
736
750
  set_bib_config(bib_config)
751
+ if glossary_config is not None:
752
+ set_glossary_config(glossary_config)
737
753
 
738
- if bib_sources:
739
- registry = get_bib_registry()
740
- for source_path in bib_sources:
741
- try:
742
- entries = load_bib(source_path)
743
- registry.register_many(entries)
744
- logger.debug(f"Loaded {len(entries)} bib entries from {source_path}")
745
- except Exception as e:
746
- logger.warning(f"Failed to load bibliography from {source_path}: {e}")
754
+ registry = get_bib_registry()
755
+ glossary = get_glossary_registry()
756
+ for source_path in bib_sources or []:
757
+ try:
758
+ entries = load_bib(source_path)
759
+ registry.register_many([e for e in entries if not is_glossary(e)])
760
+ glossary.register_many([e for e in entries if is_glossary(e)])
761
+ logger.debug(f"Loaded {len(entries)} bib entries from {source_path}")
762
+ except Exception as e:
763
+ logger.warning(f"Failed to load bibliography from {source_path}: {e}")
764
+ for source_path in glossary_sources or []:
765
+ try:
766
+ glossary.register_many(load_glossary(source_path))
767
+ except Exception as e:
768
+ logger.warning(f"Failed to load glossary from {source_path}: {e}")
747
769
 
748
770
 
749
771
  def _inject_bib_preview_if_enabled():
@@ -779,7 +801,9 @@ def _st_book_impl(module_list, toc_config: TOCConfig = None, marker_config: Mark
779
801
  lang: str | None = None,
780
802
  html_export_zoom: int = 0,
781
803
  notice=None,
782
- printable: bool | PrintConfig = True):
804
+ printable: bool | PrintConfig = True,
805
+ glossary_sources=None, glossary_config=None,
806
+ stage=(1920, 1080)):
783
807
  """Generates a web page e-book from a list of block modules.
784
808
 
785
809
  :param separator: Optional module with a build() function, rendered between each block.
@@ -811,6 +835,15 @@ def _st_book_impl(module_list, toc_config: TOCConfig = None, marker_config: Mark
811
835
  :param banner: Optional BannerConfig for full banner customisation (overrides banner_color).
812
836
  :param bib_sources: Optional list of paths to .bib, .json, .ris, or .csl-json files.
813
837
  :param bib_config: Optional BibConfig to configure bibliography formatting.
838
+ :param glossary_sources: Optional list of glossary files for ``gloss()``:
839
+ ``.yaml``/``.yml``, ``.json`` (``{"LLM": "Large Language Model"}``)
840
+ or ``.bib`` (its ``@glossary`` entries). See ``streamtex.glossary``.
841
+ :param glossary_config: Optional GlossaryConfig (``strict=True``: an unknown key raises).
842
+ :param stage: Size of the stage (#105): ``(1920, 1080)`` (default),
843
+ ``[w, h]`` or ``"WxH"``. A link under the zoom controls, and in the
844
+ HTML export's sidebar, opens the document in a virtual screen of this
845
+ size scaled to the window, with black bands (``?stage=WxH`` in the
846
+ URL). ``False``: no stage.
814
847
  :param inspector: Optional InspectorConfig to enable the block inspector panel.
815
848
  :param page_width: Page width as % of browser width (default 90).
816
849
  :param zoom: Default zoom level as % (default 100).
@@ -862,6 +895,10 @@ def _st_book_impl(module_list, toc_config: TOCConfig = None, marker_config: Mark
862
895
  _block_kwargs = dict(block_kwargs or {})
863
896
  # --- Usage notice and print rules (#107): read by the panel and every export ---
864
897
  st.session_state[PRINT_KEY] = print_state(printable, notice, _block_kwargs.get("lang"))
898
+ # --- Stage size (#105): the sidebar link, and the HTML export's ---
899
+ from .stage import parse_stage, render_stage, requested_stage
900
+ _stage = parse_stage(stage)
901
+ st.session_state[STAGE_KEY] = _stage
865
902
  # --- Resolve PdfConfig from exports list if not provided directly ---
866
903
  if pdf_config is None and exports:
867
904
  for _ecfg in exports:
@@ -901,13 +938,19 @@ def _st_book_impl(module_list, toc_config: TOCConfig = None, marker_config: Mark
901
938
  if _warmup_mode:
902
939
  # The references first: an HTML export without them shows every
903
940
  # citation as [key?] and an empty bibliography.
904
- _setup_bibliography(bib_sources, bib_config)
941
+ _setup_bibliography(bib_sources, bib_config, glossary_sources, glossary_config)
905
942
  _warmup_build_cache(module_list, toc_config, marker_config,
906
943
  separator,
907
944
  block_args=_block_args,
908
945
  block_kwargs=_block_kwargs)
909
946
  return
910
947
 
948
+ # --- Stage (#105): this tab only frames the document, which has its own gate ---
949
+ _stage_now = requested_stage(_query_params(), _stage)
950
+ if _stage_now:
951
+ render_stage(_stage_now)
952
+ return
953
+
911
954
  # --- Password gate (env-driven, no-op locally) ---
912
955
  _password_gate()
913
956
 
@@ -936,7 +979,7 @@ def _st_book_impl(module_list, toc_config: TOCConfig = None, marker_config: Mark
936
979
  st.session_state[_STX_THEME_BG_KEY] = _bg
937
980
  st.session_state[_STX_THEME_TEXT_KEY] = _txt
938
981
  # --- Bibliography setup ---
939
- _setup_bibliography(bib_sources, bib_config)
982
+ _setup_bibliography(bib_sources, bib_config, glossary_sources, glossary_config)
940
983
  # --- Presentation profiles ---
941
984
  default_profile = build_default_profile(page_width, zoom, paginate)
942
985
  user_profiles = presentation_profiles or []
@@ -1052,6 +1095,9 @@ def _st_book_impl(module_list, toc_config: TOCConfig = None, marker_config: Mark
1052
1095
  )
1053
1096
  add_zoom_options(default_page_width=page_width, default_zoom=zoom,
1054
1097
  container=_stx_settings)
1098
+ if _stage:
1099
+ from .stage import stage_link
1100
+ stage_link(_query_params(), _stage, container=_stx_settings)
1055
1101
  add_wrap_all_option(container=_stx_settings)
1056
1102
  _stx_settings.divider()
1057
1103
  add_slide_break_options(container=_stx_settings)
@@ -1949,6 +1995,14 @@ _STX_PAGE_KEY = "_stx_current_page"
1949
1995
  _STX_INITIAL_MARKER_KEY = "_stx_initial_marker"
1950
1996
 
1951
1997
 
1998
+ def _query_params() -> dict:
1999
+ """The URL's query parameters; ``{}`` outside a real script run (tests, headless)."""
2000
+ try:
2001
+ return st.query_params.to_dict()
2002
+ except Exception: # noqa: BLE001 -- no script context / mocked st
2003
+ return {}
2004
+
2005
+
1952
2006
  def _initial_page_from_url(cache, total) -> tuple[int, int | None]:
1953
2007
  """Resolve the first page of the session from the URL (deep link).
1954
2008
 
@@ -2752,7 +2806,9 @@ def _build_page_cache(module_list, toc_config, marker_config, separator,
2752
2806
  # Persist cited bibliography keys so st_bibliography(only_cited=True) works
2753
2807
  # in paginated mode (cite() calls only run during cache build, not per-page).
2754
2808
  from .bib import get_bib_registry as _get_bib_registry
2809
+ from .glossary import get_glossary_registry as _get_glossary_registry
2755
2810
  _bib_cited = list(_get_bib_registry()._cited)
2811
+ _gloss_used = list(_get_glossary_registry()._used) # st_glossary(only_used=True) (#12)
2756
2812
 
2757
2813
  st.session_state[_STX_CACHE_KEY] = {
2758
2814
  "hash": cache_hash,
@@ -2764,6 +2820,7 @@ def _build_page_cache(module_list, toc_config, marker_config, separator,
2764
2820
  "pages": pages,
2765
2821
  "search_index": search_index,
2766
2822
  "cited_keys": _bib_cited,
2823
+ "glossary_used": _gloss_used,
2767
2824
  "doc_version": st.session_state.get("_stx_doc_version", ""),
2768
2825
  "lib_version": st.session_state.get("_stx_lib_version", ""),
2769
2826
  # Data files the blocks read through stx.load_*/watch_file during
@@ -3553,6 +3610,10 @@ def _paginated_book(module_list, toc_config, marker_config, separator,
3553
3610
  for _key in cache["cited_keys"]:
3554
3611
  if _key not in _bib_reg._cited:
3555
3612
  _bib_reg._cited.append(_key)
3613
+ if cache.get("glossary_used"):
3614
+ from .glossary import get_glossary_registry as _get_gloss_reg
3615
+ for _key in cache["glossary_used"]:
3616
+ _get_gloss_reg().use(_key)
3556
3617
 
3557
3618
  # --- Banner — page titles for navigation labels ---
3558
3619
  page_titles = _get_page_titles(cache, total)
@@ -3783,6 +3844,7 @@ def _paginated_book(module_list, toc_config, marker_config, separator,
3783
3844
  BOOK_DEFAULT_KEYS = frozenset({
3784
3845
  "paginate", "paginate_by", "html_export_mode", "page_width", "zoom", "export", "export_title", "loading",
3785
3846
  "chrome_banner", "banner_color", "doc_version", "lang", "html_export_zoom",
3847
+ "stage", # stage = [1920, 1080] (#105)
3786
3848
  })
3787
3849
 
3788
3850
 
@@ -3855,7 +3917,7 @@ _DEFAULTS_DOC = """Generates a web page e-book from a list of block modules.
3855
3917
  taken from ``[book.defaults]`` of the project's ``stx.toml`` when it
3856
3918
  declares them (``paginate``, ``page_width``, ``zoom``, ``export``,
3857
3919
  ``export_title``, ``loading``, ``chrome_banner``, ``banner_color``,
3858
- ``doc_version``, ``lang``), then from the defaults below.
3920
+ ``doc_version``, ``lang``, ``stage``), then from the defaults below.
3859
3921
  ``doc_version="auto"`` reads ``[project].version`` of ``pyproject.toml``.
3860
3922
  """
3861
3923
 
@@ -286,6 +286,12 @@ def install_profile(claude_repo: str, profile: str, target: str) -> list[str]:
286
286
  if rendered and rendered not in installed:
287
287
  installed.append(rendered)
288
288
 
289
+ # The styles reference, generated from the code after the read-only copies (#6)
290
+ from .styles_cmd import refresh_reference
291
+ styles_ref = refresh_reference(target)
292
+ if styles_ref:
293
+ installed.append(styles_ref)
294
+
289
295
  return sorted(installed)
290
296
 
291
297
 
@@ -294,6 +300,7 @@ _GENERATED_PATHS = frozenset({
294
300
  os.path.join(".claude", ".stx-profile"),
295
301
  os.path.join(".claude", "CLAUDE.md"), # profile text when the root CLAUDE.md is the user's
296
302
  os.path.join(".claude", "stx.lock"), # project mode lock file
303
+ os.path.join(".claude", "references", "streamtex_styles_api.md"), # stx styles dump (#6)
297
304
  })
298
305
 
299
306
 
@@ -1209,6 +1216,12 @@ def _update_single_target(
1209
1216
  "Claude Code reads both files.[/dim]"
1210
1217
  )
1211
1218
 
1219
+ # The styles reference, regenerated when the version or its inputs changed (#6)
1220
+ from .styles_cmd import refresh_reference
1221
+ styles_ref = refresh_reference(target)
1222
+ if styles_ref:
1223
+ updated.append(styles_ref)
1224
+
1212
1225
  if updated:
1213
1226
  console.print(f"\n[green]Updated {len(updated)} file(s).[/green]")
1214
1227
  for f in updated:
@@ -391,10 +391,13 @@ def sync_project(
391
391
 
392
392
  claude_dir = os.path.join(target, ".claude")
393
393
  if remove:
394
- for rel in (os.path.join(".claude", ".stx-profile"), LOCK_PATH):
394
+ from .styles_cmd import REFERENCE
395
+ for rel in (os.path.join(".claude", ".stx-profile"), LOCK_PATH, REFERENCE):
395
396
  p = os.path.join(target, rel)
396
397
  if os.path.isfile(p):
398
+ os.chmod(p, 0o644)
397
399
  os.remove(p)
400
+ _remove_empty_dirs(target, [REFERENCE])
398
401
  if lock and lock.claude_md and lock.claude_md_sha:
399
402
  p = os.path.join(target, lock.claude_md)
400
403
  if os.path.isfile(p) and sha256_file(p) == lock.claude_md_sha:
@@ -439,6 +442,10 @@ def sync_project(
439
442
  claude_md=claude_md, claude_md_sha=claude_md_sha, files=new_files,
440
443
  ))
441
444
  _ensure_gitignore(target, console)
445
+ # The styles reference, generated from the code (#6): never in the lock, never pruned
446
+ from .styles_cmd import refresh_reference
447
+ if refresh_reference(target):
448
+ console.print(" [green]✓[/green] .claude/references/streamtex_styles_api.md (generated)")
442
449
  return plan
443
450
 
444
451
 
@@ -64,6 +64,7 @@ from .run_cmd import run as stx_run
64
64
  from .screenshot_cmd import screenshot as stx_screenshot
65
65
  from .shortcuts import run_lint, run_test
66
66
  from .status_cmd import status as workspace_status
67
+ from .styles_cmd import styles as styles_group
67
68
  from .sync_cmd import sync as stx_sync
68
69
  from .upgrade_cmd import upgrade as project_upgrade
69
70
  from .validate_cmd import validate as stx_validate
@@ -217,6 +218,7 @@ cli.add_command(ds_group, name="ds")
217
218
  cli.add_command(kit_group, name="kit")
218
219
  cli.add_command(artifact_group, name="artifact")
219
220
  cli.add_command(stx_validate, name="validate")
221
+ cli.add_command(styles_group, name="styles")
220
222
 
221
223
 
222
224
  # --- Dev subgroup ----------------------------------------------------------
@@ -263,6 +263,8 @@ def export_html(path, output, asset_mode, title, no_nav, theme_mode, theme_bg, t
263
263
  _cache_data = st.session_state.get(_book_mod._STX_CACHE_KEY) or {}
264
264
  from ..printing import get_print_state
265
265
  print_rules = get_print_state(st.session_state) # notice, html_print (#107)
266
+ from ..stage import STAGE_KEY
267
+ stage_size = st.session_state.get(STAGE_KEY) # the sidebar's stage link (#105)
266
268
 
267
269
  elapsed = time.time() - t0
268
270
 
@@ -343,6 +345,7 @@ def export_html(path, output, asset_mode, title, no_nav, theme_mode, theme_bg, t
343
345
  lib_version=_cache_data.get("lib_version", ""),
344
346
  page_nav=page_nav,
345
347
  notice=print_rules["notice"],
348
+ stage=stage_size,
346
349
  )
347
350
 
348
351
  if not no_nav and nav_data:
@@ -27,6 +27,16 @@ def _passwords(cfg):
27
27
  return pw.load_file(pw.passwords_path(cfg.root))
28
28
 
29
29
 
30
+ def _require_running(t, apps) -> None:
31
+ """The containers the command needs run, checked before an export: a wrong --target used to fail at the
32
+ first reload, after the export (all-trainings, 2026-10-29: 25 s, then "No such container: stx-static")."""
33
+ down = [a for a in sorted(set(apps)) if not t.running(a)]
34
+ if down:
35
+ hint = "start them (stx release local up) or " if t.kind == "local" else ""
36
+ raise ReleaseError(f"target {t.name}: the {' and '.join(down)} container(s) do not run — "
37
+ f"{hint}choose another --target")
38
+
39
+
30
40
  _target = click.option("--target", "target", default=None, help="Target name in .stx-release.json "
31
41
  "(default: its default_target).")
32
42
 
@@ -83,6 +93,7 @@ def publish_cmd(sites, groups, all_, target, allow_skew, html_env):
83
93
  raise ReleaseError("name the sites to publish, a --group, or --all for every site")
84
94
  cfg, state, t = _ctx(target)
85
95
  chosen = cfg.select(sites, groups)
96
+ _require_running(t, ["static" if f == "html" else "live" for s in chosen for f in s.faces])
86
97
  env = _html_env(html_env)
87
98
  release_name = build.require_committed(cfg.root)
88
99
  build.require_lock(cfg)
@@ -160,6 +171,7 @@ def limit_cmd(site, slide, labels, target, allow_skew, html_env):
160
171
  s = cfg.site(site)
161
172
  if "html" not in s.faces:
162
173
  raise ReleaseError(f"{s.site} has no HTML face: a slide limit applies to the HTML face")
174
+ _require_running(t, ["static"])
163
175
  _skew(cfg, t, allow_skew)
164
176
  if labels:
165
177
  names = [x.strip() for x in labels.split(",") if x.strip()]