@kortix/sandbox 0.4.1

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 (246) hide show
  1. package/config/customize.sh +143 -0
  2. package/config/kortix-env-setup.sh +25 -0
  3. package/kortix-master/package.json +22 -0
  4. package/kortix-master/src/config.ts +22 -0
  5. package/kortix-master/src/index.ts +44 -0
  6. package/kortix-master/src/routes/env.ts +65 -0
  7. package/kortix-master/src/routes/proxy.ts +108 -0
  8. package/kortix-master/src/routes/update.ts +185 -0
  9. package/kortix-master/src/services/proxy.ts +43 -0
  10. package/kortix-master/src/services/secret-store.ts +156 -0
  11. package/kortix-master/tsconfig.json +14 -0
  12. package/opencode/agents/kortix-browser.md +142 -0
  13. package/opencode/agents/kortix-build.md +62 -0
  14. package/opencode/agents/kortix-explore.md +66 -0
  15. package/opencode/agents/kortix-image-gen.md +33 -0
  16. package/opencode/agents/kortix-main.md +450 -0
  17. package/opencode/agents/kortix-plan.md +100 -0
  18. package/opencode/agents/kortix-research.md +84 -0
  19. package/opencode/agents/kortix-sheets.md +61 -0
  20. package/opencode/agents/kortix-slides.md +64 -0
  21. package/opencode/agents/kortix-web-dev.md +572 -0
  22. package/opencode/commands/email.md +36 -0
  23. package/opencode/commands/init.md +43 -0
  24. package/opencode/commands/journal.md +44 -0
  25. package/opencode/commands/memory-init.md +81 -0
  26. package/opencode/commands/memory-search.md +50 -0
  27. package/opencode/commands/memory-status.md +56 -0
  28. package/opencode/commands/research.md +36 -0
  29. package/opencode/commands/search.md +38 -0
  30. package/opencode/commands/slides.md +32 -0
  31. package/opencode/commands/spreadsheet.md +30 -0
  32. package/opencode/memory.json +37 -0
  33. package/opencode/ocx.jsonc +10 -0
  34. package/opencode/opencode.jsonc +103 -0
  35. package/opencode/package.json +25 -0
  36. package/opencode/patches/apply.sh +19 -0
  37. package/opencode/patches/opencode-pty-spawn.txt +49 -0
  38. package/opencode/plugin/background-agents.ts.disabled +483 -0
  39. package/opencode/plugin/kdco-primitives/get-project-id.ts +172 -0
  40. package/opencode/plugin/kdco-primitives/index.ts +26 -0
  41. package/opencode/plugin/kdco-primitives/log-warn.ts +51 -0
  42. package/opencode/plugin/kdco-primitives/mutex.ts +122 -0
  43. package/opencode/plugin/kdco-primitives/shell.ts +138 -0
  44. package/opencode/plugin/kdco-primitives/temp.ts +36 -0
  45. package/opencode/plugin/kdco-primitives/terminal-detect.ts +34 -0
  46. package/opencode/plugin/kdco-primitives/types.ts +13 -0
  47. package/opencode/plugin/kdco-primitives/with-timeout.ts +84 -0
  48. package/opencode/plugin/memory.ts +306 -0
  49. package/opencode/plugin/worktree/state.ts +412 -0
  50. package/opencode/plugin/worktree/terminal.ts +1002 -0
  51. package/opencode/plugin/worktree.ts +861 -0
  52. package/opencode/skills/KORTIX-browser/SKILL.md +478 -0
  53. package/opencode/skills/KORTIX-cron-triggers/SKILL.md +173 -0
  54. package/opencode/skills/KORTIX-deep-research/SKILL.md +278 -0
  55. package/opencode/skills/KORTIX-docx/SKILL.md +398 -0
  56. package/opencode/skills/KORTIX-docx/scripts/__init__.py +1 -0
  57. package/opencode/skills/KORTIX-docx/scripts/accept_changes.py +104 -0
  58. package/opencode/skills/KORTIX-docx/scripts/comment.py +244 -0
  59. package/opencode/skills/KORTIX-docx/scripts/office/helpers/__init__.py +0 -0
  60. package/opencode/skills/KORTIX-docx/scripts/office/helpers/merge_runs.py +199 -0
  61. package/opencode/skills/KORTIX-docx/scripts/office/helpers/simplify_redlines.py +197 -0
  62. package/opencode/skills/KORTIX-docx/scripts/office/pack.py +159 -0
  63. package/opencode/skills/KORTIX-docx/scripts/office/soffice.py +183 -0
  64. package/opencode/skills/KORTIX-docx/scripts/office/unpack.py +132 -0
  65. package/opencode/skills/KORTIX-docx/scripts/office/validate.py +111 -0
  66. package/opencode/skills/KORTIX-docx/scripts/office/validators/__init__.py +15 -0
  67. package/opencode/skills/KORTIX-docx/scripts/office/validators/base.py +847 -0
  68. package/opencode/skills/KORTIX-docx/scripts/office/validators/docx.py +446 -0
  69. package/opencode/skills/KORTIX-docx/scripts/office/validators/pptx.py +275 -0
  70. package/opencode/skills/KORTIX-docx/scripts/office/validators/redlining.py +247 -0
  71. package/opencode/skills/KORTIX-docx/scripts/render_docx.py +179 -0
  72. package/opencode/skills/KORTIX-docx/scripts/templates/comments.xml +3 -0
  73. package/opencode/skills/KORTIX-docx/scripts/templates/commentsExtended.xml +3 -0
  74. package/opencode/skills/KORTIX-docx/scripts/templates/commentsExtensible.xml +3 -0
  75. package/opencode/skills/KORTIX-docx/scripts/templates/commentsIds.xml +3 -0
  76. package/opencode/skills/KORTIX-docx/scripts/templates/people.xml +3 -0
  77. package/opencode/skills/KORTIX-domain-research/SKILL.md +96 -0
  78. package/opencode/skills/KORTIX-domain-research/scripts/domain-lookup.py +810 -0
  79. package/opencode/skills/KORTIX-elevenlabs/SKILL.md +230 -0
  80. package/opencode/skills/KORTIX-elevenlabs/scripts/tts.py +389 -0
  81. package/opencode/skills/KORTIX-email/SKILL.md +145 -0
  82. package/opencode/skills/KORTIX-legal-writer/SKILL.md +409 -0
  83. package/opencode/skills/KORTIX-legal-writer/references/bluebook.md +152 -0
  84. package/opencode/skills/KORTIX-legal-writer/references/document-types.md +416 -0
  85. package/opencode/skills/KORTIX-legal-writer/scripts/courtlistener.py +291 -0
  86. package/opencode/skills/KORTIX-legal-writer/scripts/ecfr_lookup.py +299 -0
  87. package/opencode/skills/KORTIX-legal-writer/scripts/verify-legal.py +507 -0
  88. package/opencode/skills/KORTIX-logo-creator/SKILL.md +293 -0
  89. package/opencode/skills/KORTIX-logo-creator/references/prompt-patterns.md +134 -0
  90. package/opencode/skills/KORTIX-logo-creator/scripts/compose_logo.py +406 -0
  91. package/opencode/skills/KORTIX-logo-creator/scripts/create_logo_sheet.py +258 -0
  92. package/opencode/skills/KORTIX-logo-creator/scripts/remove_bg.py +96 -0
  93. package/opencode/skills/KORTIX-memory/SKILL.md +261 -0
  94. package/opencode/skills/KORTIX-memory/scripts/export-sessions.py +409 -0
  95. package/opencode/skills/KORTIX-paper-creator/SKILL.md +549 -0
  96. package/opencode/skills/KORTIX-paper-creator/assets/template.tex +101 -0
  97. package/opencode/skills/KORTIX-paper-creator/scripts/compile.sh +177 -0
  98. package/opencode/skills/KORTIX-paper-creator/scripts/openalex_to_bibtex.py +220 -0
  99. package/opencode/skills/KORTIX-paper-creator/scripts/verify.sh +354 -0
  100. package/opencode/skills/KORTIX-paper-search/SKILL.md +418 -0
  101. package/opencode/skills/KORTIX-pdf/SKILL.md +232 -0
  102. package/opencode/skills/KORTIX-pdf/forms.md +36 -0
  103. package/opencode/skills/KORTIX-pdf/reference.md +105 -0
  104. package/opencode/skills/KORTIX-pdf/scripts/check_bounding_boxes.py +65 -0
  105. package/opencode/skills/KORTIX-pdf/scripts/check_fillable_fields.py +11 -0
  106. package/opencode/skills/KORTIX-pdf/scripts/convert_pdf_to_images.py +33 -0
  107. package/opencode/skills/KORTIX-pdf/scripts/create_validation_image.py +37 -0
  108. package/opencode/skills/KORTIX-pdf/scripts/extract_form_field_info.py +122 -0
  109. package/opencode/skills/KORTIX-pdf/scripts/extract_form_structure.py +115 -0
  110. package/opencode/skills/KORTIX-pdf/scripts/fill_fillable_fields.py +98 -0
  111. package/opencode/skills/KORTIX-pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
  112. package/opencode/skills/KORTIX-plan/SKILL.md +228 -0
  113. package/opencode/skills/KORTIX-presentation-viewer/SKILL.md +87 -0
  114. package/opencode/skills/KORTIX-presentation-viewer/serve.ts +136 -0
  115. package/opencode/skills/KORTIX-presentation-viewer/viewer.html +559 -0
  116. package/opencode/skills/KORTIX-presentations/SKILL.md +344 -0
  117. package/opencode/skills/KORTIX-remotion/SKILL.md +56 -0
  118. package/opencode/skills/KORTIX-remotion/rules/3d.md +86 -0
  119. package/opencode/skills/KORTIX-remotion/rules/animations.md +29 -0
  120. package/opencode/skills/KORTIX-remotion/rules/assets.md +78 -0
  121. package/opencode/skills/KORTIX-remotion/rules/audio-visualization.md +198 -0
  122. package/opencode/skills/KORTIX-remotion/rules/audio.md +169 -0
  123. package/opencode/skills/KORTIX-remotion/rules/calculate-metadata.md +104 -0
  124. package/opencode/skills/KORTIX-remotion/rules/can-decode.md +75 -0
  125. package/opencode/skills/KORTIX-remotion/rules/charts.md +120 -0
  126. package/opencode/skills/KORTIX-remotion/rules/compositions.md +141 -0
  127. package/opencode/skills/KORTIX-remotion/rules/display-captions.md +184 -0
  128. package/opencode/skills/KORTIX-remotion/rules/extract-frames.md +229 -0
  129. package/opencode/skills/KORTIX-remotion/rules/ffmpeg.md +38 -0
  130. package/opencode/skills/KORTIX-remotion/rules/fonts.md +152 -0
  131. package/opencode/skills/KORTIX-remotion/rules/get-audio-duration.md +58 -0
  132. package/opencode/skills/KORTIX-remotion/rules/get-video-dimensions.md +68 -0
  133. package/opencode/skills/KORTIX-remotion/rules/get-video-duration.md +58 -0
  134. package/opencode/skills/KORTIX-remotion/rules/gifs.md +141 -0
  135. package/opencode/skills/KORTIX-remotion/rules/images.md +130 -0
  136. package/opencode/skills/KORTIX-remotion/rules/import-srt-captions.md +69 -0
  137. package/opencode/skills/KORTIX-remotion/rules/light-leaks.md +73 -0
  138. package/opencode/skills/KORTIX-remotion/rules/lottie.md +68 -0
  139. package/opencode/skills/KORTIX-remotion/rules/maps.md +401 -0
  140. package/opencode/skills/KORTIX-remotion/rules/measuring-dom-nodes.md +35 -0
  141. package/opencode/skills/KORTIX-remotion/rules/measuring-text.md +143 -0
  142. package/opencode/skills/KORTIX-remotion/rules/parameters.md +98 -0
  143. package/opencode/skills/KORTIX-remotion/rules/sequencing.md +118 -0
  144. package/opencode/skills/KORTIX-remotion/rules/subtitles.md +36 -0
  145. package/opencode/skills/KORTIX-remotion/rules/tailwind.md +11 -0
  146. package/opencode/skills/KORTIX-remotion/rules/text-animations.md +20 -0
  147. package/opencode/skills/KORTIX-remotion/rules/timing.md +179 -0
  148. package/opencode/skills/KORTIX-remotion/rules/transcribe-captions.md +70 -0
  149. package/opencode/skills/KORTIX-remotion/rules/transitions.md +197 -0
  150. package/opencode/skills/KORTIX-remotion/rules/transparent-videos.md +106 -0
  151. package/opencode/skills/KORTIX-remotion/rules/trimming.md +53 -0
  152. package/opencode/skills/KORTIX-remotion/rules/videos.md +171 -0
  153. package/opencode/skills/KORTIX-secrets/SKILL.md +280 -0
  154. package/opencode/skills/KORTIX-semantic-search/SKILL.md +213 -0
  155. package/opencode/skills/KORTIX-session-search/SKILL.md +807 -0
  156. package/opencode/skills/KORTIX-session-search/Untitled +1 -0
  157. package/opencode/skills/KORTIX-skill-creator/SKILL.md +163 -0
  158. package/opencode/skills/KORTIX-web-research/SKILL.md +69 -0
  159. package/opencode/skills/KORTIX-xlsx/LICENSE.txt +30 -0
  160. package/opencode/skills/KORTIX-xlsx/SKILL.md +549 -0
  161. package/opencode/skills/KORTIX-xlsx/scripts/office/helpers/__init__.py +0 -0
  162. package/opencode/skills/KORTIX-xlsx/scripts/office/helpers/merge_runs.py +199 -0
  163. package/opencode/skills/KORTIX-xlsx/scripts/office/helpers/simplify_redlines.py +197 -0
  164. package/opencode/skills/KORTIX-xlsx/scripts/office/pack.py +159 -0
  165. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  166. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  167. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  168. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  169. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  170. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  171. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  172. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  173. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  174. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  175. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  176. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  177. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  178. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  179. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  180. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  181. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  182. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  183. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  184. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  185. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  186. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  187. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  188. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  189. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  190. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  191. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  192. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  193. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  194. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  195. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  196. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/mce/mc.xsd +75 -0
  197. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  198. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  199. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  200. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  201. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  202. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  203. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  204. package/opencode/skills/KORTIX-xlsx/scripts/office/soffice.py +183 -0
  205. package/opencode/skills/KORTIX-xlsx/scripts/office/unpack.py +132 -0
  206. package/opencode/skills/KORTIX-xlsx/scripts/office/validate.py +111 -0
  207. package/opencode/skills/KORTIX-xlsx/scripts/office/validators/__init__.py +15 -0
  208. package/opencode/skills/KORTIX-xlsx/scripts/office/validators/base.py +847 -0
  209. package/opencode/skills/KORTIX-xlsx/scripts/office/validators/docx.py +446 -0
  210. package/opencode/skills/KORTIX-xlsx/scripts/office/validators/pptx.py +275 -0
  211. package/opencode/skills/KORTIX-xlsx/scripts/office/validators/redlining.py +247 -0
  212. package/opencode/skills/KORTIX-xlsx/scripts/recalc.py +184 -0
  213. package/opencode/tools/image-gen.ts +342 -0
  214. package/opencode/tools/image-search.ts +190 -0
  215. package/opencode/tools/memory-get.ts +168 -0
  216. package/opencode/tools/memory-search.ts +247 -0
  217. package/opencode/tools/presentation-gen.ts +723 -0
  218. package/opencode/tools/scrape-webpage.ts +115 -0
  219. package/opencode/tools/scripts/.python-version +1 -0
  220. package/opencode/tools/scripts/convert_pdf.py +184 -0
  221. package/opencode/tools/scripts/convert_pptx.py +562 -0
  222. package/opencode/tools/scripts/pyproject.toml +11 -0
  223. package/opencode/tools/scripts/uv.lock +287 -0
  224. package/opencode/tools/scripts/validate_slide.py +74 -0
  225. package/opencode/tools/show-user.ts +217 -0
  226. package/opencode/tools/tests/e2e-presentation-fix.ts +277 -0
  227. package/opencode/tools/tests/image-gen.test.ts +215 -0
  228. package/opencode/tools/tests/image-search.test.ts +125 -0
  229. package/opencode/tools/tests/memory-system-benchmark.ts +1076 -0
  230. package/opencode/tools/tests/presentation-gen.test.ts +389 -0
  231. package/opencode/tools/tests/scrape-webpage.test.ts +74 -0
  232. package/opencode/tools/tests/show-user.test.ts +241 -0
  233. package/opencode/tools/tests/video-gen.test.ts +110 -0
  234. package/opencode/tools/tests/web-search.test.ts +106 -0
  235. package/opencode/tools/video-gen.ts +200 -0
  236. package/opencode/tools/web-search.ts +153 -0
  237. package/opencode/tsconfig.json +29 -0
  238. package/package.json +36 -0
  239. package/patch-agent-browser.js +100 -0
  240. package/postinstall.sh +88 -0
  241. package/services/KORTIX-presentation-viewer/run +37 -0
  242. package/services/agent-browser-viewer/run +48 -0
  243. package/services/kortix-master/run +16 -0
  244. package/services/lss-sync/run +22 -0
  245. package/services/opencode-serve/run +25 -0
  246. package/services/opencode-web/run +21 -0
@@ -0,0 +1,559 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>{{TITLE}}</title>
7
+ <style>
8
+ *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
9
+
10
+ :root {
11
+ --bg: #09090b;
12
+ --surface: #18181b;
13
+ --border: #27272a;
14
+ --text: #e4e4e7;
15
+ --text-dim: #71717a;
16
+ --accent: #3b82f6;
17
+ --accent-dim: rgba(59, 130, 246, 0.12);
18
+ }
19
+
20
+ html, body {
21
+ width: 100%; height: 100%;
22
+ overflow: hidden;
23
+ background: var(--bg);
24
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
25
+ color: var(--text);
26
+ user-select: none;
27
+ -webkit-user-select: none;
28
+ }
29
+
30
+ .viewer {
31
+ display: flex;
32
+ flex-direction: column;
33
+ width: 100vw;
34
+ height: 100vh;
35
+ }
36
+
37
+ /* ── Stage ── */
38
+ .stage {
39
+ flex: 1 1 0;
40
+ min-height: 0;
41
+ display: flex;
42
+ align-items: center;
43
+ justify-content: center;
44
+ position: relative;
45
+ overflow: hidden;
46
+ }
47
+
48
+ /*
49
+ The wrapper is sized to the ACTUAL displayed pixel size (not 1920x1080).
50
+ JS sets --sw and --sh to the real rendered width/height.
51
+ Inside, the 1920x1080 iframe is scaled down via transform.
52
+ */
53
+ .slide-frame-wrapper {
54
+ position: relative;
55
+ overflow: hidden;
56
+ border-radius: 6px;
57
+ box-shadow:
58
+ 0 0 0 1px rgba(255,255,255,0.06),
59
+ 0 8px 40px rgba(0,0,0,0.5),
60
+ 0 30px 80px rgba(0,0,0,0.4);
61
+ }
62
+
63
+ .slide-frame {
64
+ width: 1920px;
65
+ height: 1080px;
66
+ border: none;
67
+ display: block;
68
+ position: absolute;
69
+ top: 0; left: 0;
70
+ transform-origin: 0 0;
71
+ visibility: hidden;
72
+ }
73
+
74
+ .slide-frame.active { visibility: visible; }
75
+
76
+ /* ── Navigation overlays ── */
77
+ .nav-zone {
78
+ position: absolute;
79
+ top: 0; height: 100%;
80
+ width: 12%;
81
+ min-width: 60px;
82
+ display: flex;
83
+ align-items: center;
84
+ z-index: 10;
85
+ opacity: 0;
86
+ transition: opacity 0.2s;
87
+ cursor: pointer;
88
+ }
89
+
90
+ .stage:hover .nav-zone { opacity: 1; }
91
+
92
+ .nav-zone--prev { left: 0; justify-content: flex-start; padding-left: 20px; }
93
+ .nav-zone--next { right: 0; justify-content: flex-end; padding-right: 20px; }
94
+
95
+ .nav-btn {
96
+ width: 44px; height: 44px;
97
+ border-radius: 50%;
98
+ background: rgba(0,0,0,0.5);
99
+ backdrop-filter: blur(12px);
100
+ -webkit-backdrop-filter: blur(12px);
101
+ border: 1px solid rgba(255,255,255,0.1);
102
+ display: flex; align-items: center; justify-content: center;
103
+ transition: all 0.15s;
104
+ color: rgba(255,255,255,0.8);
105
+ }
106
+
107
+ .nav-btn:hover { background: rgba(0,0,0,0.7); color: #fff; transform: scale(1.1); }
108
+
109
+ .nav-btn svg {
110
+ width: 20px; height: 20px;
111
+ fill: none; stroke: currentColor; stroke-width: 2.5;
112
+ stroke-linecap: round; stroke-linejoin: round;
113
+ }
114
+
115
+ .nav-zone.disabled { pointer-events: none; }
116
+ .nav-zone.disabled .nav-btn { opacity: 0.15; }
117
+
118
+ /* ── Bottom bar ── */
119
+ .bottom-bar {
120
+ height: 48px; min-height: 48px;
121
+ display: flex; align-items: center; justify-content: space-between;
122
+ padding: 0 16px;
123
+ background: var(--surface);
124
+ border-top: 1px solid var(--border);
125
+ z-index: 20;
126
+ gap: 12px;
127
+ }
128
+
129
+ .bottom-section {
130
+ display: flex; align-items: center; gap: 6px;
131
+ }
132
+
133
+ .bottom-section.left { flex: 1; min-width: 0; }
134
+ .bottom-section.center { flex: 0 0 auto; }
135
+ .bottom-section.right { flex: 1; min-width: 0; justify-content: flex-end; }
136
+
137
+ .slide-counter {
138
+ font-size: 13px; font-weight: 600;
139
+ color: var(--text);
140
+ font-variant-numeric: tabular-nums;
141
+ white-space: nowrap;
142
+ }
143
+
144
+ .slide-counter .dim { color: var(--text-dim); font-weight: 400; }
145
+
146
+ .slide-title-display {
147
+ font-size: 12px; color: var(--text-dim);
148
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
149
+ min-width: 0;
150
+ }
151
+
152
+ .pres-title {
153
+ font-size: 12px; font-weight: 500; color: var(--text-dim);
154
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
155
+ min-width: 0;
156
+ }
157
+
158
+ .sep { color: var(--border); font-size: 14px; }
159
+
160
+ /* ── Toolbar buttons ── */
161
+ .tb {
162
+ width: 32px; height: 32px;
163
+ border-radius: 6px; border: none;
164
+ background: transparent; color: var(--text-dim);
165
+ display: flex; align-items: center; justify-content: center;
166
+ cursor: pointer; transition: all 0.12s; flex-shrink: 0;
167
+ }
168
+
169
+ .tb:hover { background: rgba(255,255,255,0.07); color: var(--text); }
170
+ .tb.active { background: var(--accent-dim); color: var(--accent); }
171
+
172
+ .tb svg {
173
+ width: 16px; height: 16px;
174
+ fill: none; stroke: currentColor; stroke-width: 2;
175
+ stroke-linecap: round; stroke-linejoin: round;
176
+ }
177
+
178
+ /* ── Progress bar ── */
179
+ .progress-track {
180
+ position: absolute; bottom: 48px; left: 0; right: 0;
181
+ height: 3px; background: rgba(255,255,255,0.04);
182
+ z-index: 15; cursor: pointer;
183
+ transition: height 0.15s;
184
+ }
185
+
186
+ .progress-fill {
187
+ height: 100%; background: var(--accent);
188
+ transition: width 0.25s ease; border-radius: 0 1px 1px 0;
189
+ }
190
+
191
+ .progress-track:hover { height: 6px; }
192
+
193
+ /* ── Thumbnail strip ── */
194
+ .thumb-strip {
195
+ position: absolute; bottom: 52px; left: 0; right: 0;
196
+ background: rgba(9,9,11,0.96);
197
+ backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
198
+ border-top: 1px solid var(--border);
199
+ padding: 14px 16px;
200
+ display: flex; gap: 10px;
201
+ overflow-x: auto; overflow-y: hidden;
202
+ z-index: 25;
203
+ transform: translateY(calc(100% + 52px)); opacity: 0;
204
+ transition: transform 0.25s ease, opacity 0.2s ease;
205
+ scrollbar-width: thin;
206
+ scrollbar-color: rgba(255,255,255,0.08) transparent;
207
+ }
208
+
209
+ .thumb-strip.open { transform: translateY(0); opacity: 1; }
210
+
211
+ .thumb-strip::-webkit-scrollbar { height: 3px; }
212
+ .thumb-strip::-webkit-scrollbar-track { background: transparent; }
213
+ .thumb-strip::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 2px; }
214
+
215
+ .thumb {
216
+ flex: 0 0 auto; width: 160px; height: 90px;
217
+ border-radius: 4px; overflow: hidden;
218
+ border: 2px solid transparent;
219
+ cursor: pointer; position: relative; background: #000;
220
+ transition: border-color 0.12s, transform 0.12s, box-shadow 0.12s;
221
+ }
222
+
223
+ .thumb:hover { border-color: rgba(255,255,255,0.2); transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.4); }
224
+ .thumb.active { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent), 0 4px 16px rgba(59,130,246,0.2); }
225
+
226
+ .thumb iframe {
227
+ width: 1920px; height: 1080px; border: none;
228
+ transform: scale(calc(160 / 1920)); transform-origin: top left;
229
+ pointer-events: none;
230
+ }
231
+
232
+ .thumb-num {
233
+ position: absolute; top: 4px; left: 4px;
234
+ width: 20px; height: 20px; border-radius: 4px;
235
+ background: rgba(0,0,0,0.7);
236
+ font-size: 10px; font-weight: 600; color: rgba(255,255,255,0.7);
237
+ display: flex; align-items: center; justify-content: center;
238
+ }
239
+
240
+ .thumb.active .thumb-num { background: var(--accent); color: #fff; }
241
+
242
+ /* ── Help overlay ── */
243
+ .overlay-bg {
244
+ position: fixed; inset: 0;
245
+ background: rgba(0,0,0,0.6); z-index: 99;
246
+ display: none;
247
+ }
248
+ .overlay-bg.open { display: block; }
249
+
250
+ .hints {
251
+ position: fixed; top: 50%; left: 50%;
252
+ transform: translate(-50%, -50%);
253
+ background: var(--surface);
254
+ border: 1px solid var(--border);
255
+ border-radius: 12px; padding: 24px 32px;
256
+ z-index: 100; display: none; min-width: 300px;
257
+ box-shadow: 0 24px 80px rgba(0,0,0,0.6);
258
+ }
259
+
260
+ .hints.open { display: block; }
261
+
262
+ .hints h3 { font-size: 15px; font-weight: 600; margin-bottom: 16px; }
263
+
264
+ .hint-row { display: flex; justify-content: space-between; align-items: center; padding: 5px 0; }
265
+ .hint-keys { display: flex; gap: 4px; }
266
+
267
+ .hint-key {
268
+ display: inline-flex; align-items: center; justify-content: center;
269
+ min-width: 26px; height: 24px; padding: 0 6px;
270
+ border-radius: 5px; background: rgba(255,255,255,0.06);
271
+ border: 1px solid rgba(255,255,255,0.1);
272
+ font-size: 11px; font-weight: 600; color: var(--text);
273
+ }
274
+
275
+ .hint-label { font-size: 13px; color: var(--text-dim); margin-left: 20px; }
276
+
277
+ /* ── Fullscreen ── */
278
+ .viewer.fullscreen .bottom-bar { height: 0; min-height: 0; overflow: hidden; border: none; padding: 0; }
279
+ .viewer.fullscreen .progress-track { bottom: 0; opacity: 0; transition: opacity 0.2s; }
280
+ .viewer.fullscreen:hover .progress-track { opacity: 1; }
281
+ .viewer.fullscreen .thumb-strip { bottom: 4px; }
282
+
283
+ /* ── Slide transition ── */
284
+ .slide-frame { transition: visibility 0s 0.15s, opacity 0.15s ease; opacity: 0; }
285
+ .slide-frame.active { transition: visibility 0s 0s, opacity 0.2s ease; opacity: 1; }
286
+ </style>
287
+ </head>
288
+ <body>
289
+
290
+ <div class="viewer" id="viewer">
291
+ <div class="stage" id="stage">
292
+ <div class="slide-frame-wrapper" id="wrapper"></div>
293
+
294
+ <div class="nav-zone nav-zone--prev" id="navPrev" onclick="prev()">
295
+ <div class="nav-btn"><svg viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg></div>
296
+ </div>
297
+ <div class="nav-zone nav-zone--next" id="navNext" onclick="next()">
298
+ <div class="nav-btn"><svg viewBox="0 0 24 24"><polyline points="9 6 15 12 9 18"/></svg></div>
299
+ </div>
300
+ </div>
301
+
302
+ <div class="progress-track" id="progressTrack" onclick="onProgressClick(event)">
303
+ <div class="progress-fill" id="progressFill"></div>
304
+ </div>
305
+
306
+ <div class="thumb-strip" id="thumbStrip"></div>
307
+
308
+ <div class="bottom-bar" id="bottomBar">
309
+ <div class="bottom-section left">
310
+ <span class="pres-title" id="presTitle"></span>
311
+ <span class="sep">|</span>
312
+ <span class="slide-title-display" id="slideTitle"></span>
313
+ </div>
314
+ <div class="bottom-section center">
315
+ <button class="tb" onclick="prev()" title="Previous (←)">
316
+ <svg viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg>
317
+ </button>
318
+ <span class="slide-counter" id="counter"></span>
319
+ <button class="tb" onclick="next()" title="Next (→)">
320
+ <svg viewBox="0 0 24 24"><polyline points="9 6 15 12 9 18"/></svg>
321
+ </button>
322
+ </div>
323
+ <div class="bottom-section right">
324
+ <button class="tb" id="btnThumbs" onclick="toggleThumbs()" title="Thumbnails (T)">
325
+ <svg viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>
326
+ </button>
327
+ <button class="tb" id="btnFS" onclick="toggleFullscreen()" title="Fullscreen (F)">
328
+ <svg viewBox="0 0 24 24"><polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/><line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/></svg>
329
+ </button>
330
+ <button class="tb" onclick="toggleHelp()" title="Help (?)">
331
+ <svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" /><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
332
+ </button>
333
+ </div>
334
+ </div>
335
+ </div>
336
+
337
+ <div class="overlay-bg" id="overlayBg" onclick="toggleHelp()"></div>
338
+ <div class="hints" id="hints">
339
+ <h3>Keyboard Shortcuts</h3>
340
+ <div class="hint-row"><div class="hint-keys"><span class="hint-key">&rarr;</span><span class="hint-key">Space</span></div><span class="hint-label">Next slide</span></div>
341
+ <div class="hint-row"><div class="hint-keys"><span class="hint-key">&larr;</span></div><span class="hint-label">Previous slide</span></div>
342
+ <div class="hint-row"><div class="hint-keys"><span class="hint-key">Home</span></div><span class="hint-label">First slide</span></div>
343
+ <div class="hint-row"><div class="hint-keys"><span class="hint-key">End</span></div><span class="hint-label">Last slide</span></div>
344
+ <div class="hint-row"><div class="hint-keys"><span class="hint-key">F</span></div><span class="hint-label">Fullscreen</span></div>
345
+ <div class="hint-row"><div class="hint-keys"><span class="hint-key">T</span></div><span class="hint-label">Thumbnails</span></div>
346
+ <div class="hint-row"><div class="hint-keys"><span class="hint-key">Esc</span></div><span class="hint-label">Exit / close</span></div>
347
+ <div class="hint-row"><div class="hint-keys"><span class="hint-key">?</span></div><span class="hint-label">This help</span></div>
348
+ </div>
349
+
350
+ <script>
351
+ const PRESENTATION = {{PRESENTATION_DATA}};
352
+ const SLIDES = PRESENTATION.slides;
353
+ const TOTAL = SLIDES.length;
354
+ const SW = 1920;
355
+ const SH = 1080;
356
+ const RATIO = SW / SH;
357
+
358
+ let current = 0;
359
+ let thumbsOpen = false;
360
+ let helpOpen = false;
361
+ let iframes = [];
362
+
363
+ const $ = (id) => document.getElementById(id);
364
+ const wrapper = $('wrapper');
365
+ const stage = $('stage');
366
+ const counter = $('counter');
367
+ const slideTitle = $('slideTitle');
368
+ const presTitle = $('presTitle');
369
+ const progressFill = $('progressFill');
370
+ const navPrev = $('navPrev');
371
+ const navNext = $('navNext');
372
+ const thumbStrip = $('thumbStrip');
373
+ const btnThumbs = $('btnThumbs');
374
+ const hints = $('hints');
375
+ const overlayBg = $('overlayBg');
376
+ const viewer = $('viewer');
377
+
378
+ function init() {
379
+ presTitle.textContent = PRESENTATION.title || 'Presentation';
380
+ document.title = PRESENTATION.title || 'Presentation';
381
+
382
+ SLIDES.forEach(function(slide, i) {
383
+ var iframe = document.createElement('iframe');
384
+ iframe.className = 'slide-frame';
385
+ iframe.src = slide.filename;
386
+ iframe.setAttribute('loading', i < 2 ? 'eager' : 'lazy');
387
+ iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
388
+ wrapper.appendChild(iframe);
389
+ iframes.push(iframe);
390
+
391
+ var thumb = document.createElement('div');
392
+ thumb.className = 'thumb';
393
+ thumb.onclick = function() { goTo(i); };
394
+
395
+ var tIframe = document.createElement('iframe');
396
+ tIframe.src = slide.filename;
397
+ tIframe.setAttribute('loading', 'lazy');
398
+ tIframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
399
+ tIframe.setAttribute('tabindex', '-1');
400
+ thumb.appendChild(tIframe);
401
+
402
+ var num = document.createElement('div');
403
+ num.className = 'thumb-num';
404
+ num.textContent = i + 1;
405
+ thumb.appendChild(num);
406
+
407
+ thumbStrip.appendChild(thumb);
408
+ });
409
+
410
+ goTo(0);
411
+ rescale();
412
+ window.addEventListener('resize', rescale);
413
+ }
414
+
415
+ function rescale() {
416
+ var isFS = viewer.classList.contains('fullscreen');
417
+ var barH = isFS ? 0 : 48;
418
+ var progressH = 3;
419
+
420
+ var stageRect = stage.getBoundingClientRect();
421
+ var availW = stageRect.width;
422
+ var availH = stageRect.height;
423
+
424
+ if (availW <= 0 || availH <= 0) {
425
+ availW = window.innerWidth;
426
+ availH = window.innerHeight - barH - progressH;
427
+ }
428
+
429
+ var pad = Math.min(availW, availH) * 0.03;
430
+ var innerW = availW - pad * 2;
431
+ var innerH = availH - pad * 2;
432
+
433
+ var scale;
434
+ if (innerW / innerH > RATIO) {
435
+ scale = innerH / SH;
436
+ } else {
437
+ scale = innerW / SW;
438
+ }
439
+
440
+ var displayW = Math.round(SW * scale);
441
+ var displayH = Math.round(SH * scale);
442
+
443
+ wrapper.style.width = displayW + 'px';
444
+ wrapper.style.height = displayH + 'px';
445
+
446
+ iframes.forEach(function(f) {
447
+ f.style.transform = 'scale(' + scale + ')';
448
+ });
449
+ }
450
+
451
+ function goTo(index) {
452
+ if (index < 0 || index >= TOTAL) return;
453
+ current = index;
454
+
455
+ iframes.forEach(function(f, i) {
456
+ f.classList.toggle('active', i === current);
457
+ });
458
+
459
+ for (var offset = -1; offset <= 2; offset++) {
460
+ var idx = current + offset;
461
+ if (idx >= 0 && idx < TOTAL && iframes[idx].getAttribute('loading') === 'lazy') {
462
+ iframes[idx].removeAttribute('loading');
463
+ iframes[idx].src = SLIDES[idx].filename;
464
+ }
465
+ }
466
+
467
+ counter.innerHTML = (current + 1) + ' <span class="dim">/ ' + TOTAL + '</span>';
468
+ slideTitle.textContent = SLIDES[current].title || '';
469
+ progressFill.style.width = ((current + 1) / TOTAL * 100).toFixed(1) + '%';
470
+
471
+ navPrev.classList.toggle('disabled', current === 0);
472
+ navNext.classList.toggle('disabled', current === TOTAL - 1);
473
+
474
+ var thumbs = thumbStrip.querySelectorAll('.thumb');
475
+ thumbs.forEach(function(t, i) { t.classList.toggle('active', i === current); });
476
+
477
+ if (thumbsOpen && thumbs[current]) {
478
+ thumbs[current].scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' });
479
+ }
480
+ }
481
+
482
+ function next() { goTo(current + 1); }
483
+ function prev() { goTo(current - 1); }
484
+
485
+ function toggleThumbs() {
486
+ thumbsOpen = !thumbsOpen;
487
+ thumbStrip.classList.toggle('open', thumbsOpen);
488
+ btnThumbs.classList.toggle('active', thumbsOpen);
489
+ if (thumbsOpen) {
490
+ var thumbs = thumbStrip.querySelectorAll('.thumb');
491
+ if (thumbs[current]) thumbs[current].scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' });
492
+ }
493
+ }
494
+
495
+ function toggleFullscreen() {
496
+ if (!document.fullscreenElement) {
497
+ document.documentElement.requestFullscreen().catch(function(){});
498
+ } else {
499
+ document.exitFullscreen().catch(function(){});
500
+ }
501
+ }
502
+
503
+ document.addEventListener('fullscreenchange', function() {
504
+ viewer.classList.toggle('fullscreen', !!document.fullscreenElement);
505
+ requestAnimationFrame(rescale);
506
+ });
507
+
508
+ function toggleHelp() {
509
+ helpOpen = !helpOpen;
510
+ hints.classList.toggle('open', helpOpen);
511
+ overlayBg.classList.toggle('open', helpOpen);
512
+ }
513
+
514
+ function onProgressClick(e) {
515
+ var rect = e.currentTarget.getBoundingClientRect();
516
+ var pct = (e.clientX - rect.left) / rect.width;
517
+ goTo(Math.min(Math.floor(pct * TOTAL), TOTAL - 1));
518
+ }
519
+
520
+ document.addEventListener('keydown', function(e) {
521
+ if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
522
+ switch (e.key) {
523
+ case 'ArrowRight': case ' ': case 'ArrowDown':
524
+ e.preventDefault(); next(); break;
525
+ case 'ArrowLeft': case 'ArrowUp':
526
+ e.preventDefault(); prev(); break;
527
+ case 'Home':
528
+ e.preventDefault(); goTo(0); break;
529
+ case 'End':
530
+ e.preventDefault(); goTo(TOTAL - 1); break;
531
+ case 'f': case 'F':
532
+ e.preventDefault(); toggleFullscreen(); break;
533
+ case 't': case 'T':
534
+ e.preventDefault(); toggleThumbs(); break;
535
+ case 'Escape':
536
+ if (helpOpen) { toggleHelp(); e.preventDefault(); }
537
+ else if (thumbsOpen) { toggleThumbs(); e.preventDefault(); }
538
+ break;
539
+ case '?':
540
+ e.preventDefault(); toggleHelp(); break;
541
+ }
542
+ });
543
+
544
+ var touchX = 0, touchY = 0;
545
+ stage.addEventListener('touchstart', function(e) {
546
+ touchX = e.touches[0].clientX; touchY = e.touches[0].clientY;
547
+ }, { passive: true });
548
+ stage.addEventListener('touchend', function(e) {
549
+ var dx = e.changedTouches[0].clientX - touchX;
550
+ var dy = e.changedTouches[0].clientY - touchY;
551
+ if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 50) {
552
+ dx < 0 ? next() : prev();
553
+ }
554
+ }, { passive: true });
555
+
556
+ init();
557
+ </script>
558
+ </body>
559
+ </html>