coursecode 0.1.0

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 (362) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +322 -0
  3. package/THIRD_PARTY_NOTICES.md +22 -0
  4. package/bin/cli.js +331 -0
  5. package/framework/assets/logo-coursecode-black.svg +14 -0
  6. package/framework/assets/logo-coursecode-white.svg +14 -0
  7. package/framework/assets/logo-coursecode.svg +14 -0
  8. package/framework/css/01-base.css +160 -0
  9. package/framework/css/02-layout.css +499 -0
  10. package/framework/css/accessibility.css +834 -0
  11. package/framework/css/components/accordions.css +710 -0
  12. package/framework/css/components/assessments.css +520 -0
  13. package/framework/css/components/audio-player.css +570 -0
  14. package/framework/css/components/badges.css +80 -0
  15. package/framework/css/components/breadcrumbs.css +87 -0
  16. package/framework/css/components/buttons.css +707 -0
  17. package/framework/css/components/callouts.css +1280 -0
  18. package/framework/css/components/cards.css +475 -0
  19. package/framework/css/components/carousel.css +193 -0
  20. package/framework/css/components/checkbox-group.css +123 -0
  21. package/framework/css/components/checklist.css +203 -0
  22. package/framework/css/components/collapse.css +96 -0
  23. package/framework/css/components/comparison.css +33 -0
  24. package/framework/css/components/content-image.css +36 -0
  25. package/framework/css/components/document-gallery.css +425 -0
  26. package/framework/css/components/dropdown.css +115 -0
  27. package/framework/css/components/embed-frame.css +142 -0
  28. package/framework/css/components/engagement.css +412 -0
  29. package/framework/css/components/features.css +35 -0
  30. package/framework/css/components/flip-cards.css +253 -0
  31. package/framework/css/components/footer.css +353 -0
  32. package/framework/css/components/forms.css +294 -0
  33. package/framework/css/components/hero.css +216 -0
  34. package/framework/css/components/images.css +528 -0
  35. package/framework/css/components/interactive-timeline.css +274 -0
  36. package/framework/css/components/intro-cards.css +30 -0
  37. package/framework/css/components/lightbox.css +666 -0
  38. package/framework/css/components/loading.css +65 -0
  39. package/framework/css/components/modals.css +235 -0
  40. package/framework/css/components/notifications.css +107 -0
  41. package/framework/css/components/quote.css +150 -0
  42. package/framework/css/components/sidebar.css +684 -0
  43. package/framework/css/components/slide-header.css +52 -0
  44. package/framework/css/components/spinner.css +62 -0
  45. package/framework/css/components/stats.css +44 -0
  46. package/framework/css/components/steps.css +232 -0
  47. package/framework/css/components/tables.css +90 -0
  48. package/framework/css/components/tabs.css +347 -0
  49. package/framework/css/components/timeline.css +154 -0
  50. package/framework/css/components/toggle.css +95 -0
  51. package/framework/css/components/tooltip.css +226 -0
  52. package/framework/css/components/video-player.css +438 -0
  53. package/framework/css/design-tokens.css +707 -0
  54. package/framework/css/framework.css +86 -0
  55. package/framework/css/interactions/accessibility.css +75 -0
  56. package/framework/css/interactions/base.css +92 -0
  57. package/framework/css/interactions/drag-drop.css +295 -0
  58. package/framework/css/interactions/fill-in-the-blank.css +236 -0
  59. package/framework/css/interactions/hotspots.css +69 -0
  60. package/framework/css/interactions/index.css +45 -0
  61. package/framework/css/interactions/interactive-image.css +359 -0
  62. package/framework/css/interactions/likert.css +126 -0
  63. package/framework/css/interactions/matching.css +354 -0
  64. package/framework/css/interactions/numeric-input.css +78 -0
  65. package/framework/css/interactions/sequencing.css +378 -0
  66. package/framework/css/interactions/true-false.css +177 -0
  67. package/framework/css/layouts/article.css +258 -0
  68. package/framework/css/layouts/base.css +30 -0
  69. package/framework/css/layouts/canvas.css +38 -0
  70. package/framework/css/layouts/focused.css +236 -0
  71. package/framework/css/layouts/index.css +29 -0
  72. package/framework/css/layouts/presentation.css +191 -0
  73. package/framework/css/layouts/traditional.css +52 -0
  74. package/framework/css/responsive.css +439 -0
  75. package/framework/css/utilities/accessibility-utils.css +59 -0
  76. package/framework/css/utilities/animations.css +419 -0
  77. package/framework/css/utilities/borders.css +72 -0
  78. package/framework/css/utilities/colors.css +76 -0
  79. package/framework/css/utilities/container.css +46 -0
  80. package/framework/css/utilities/decorative.css +442 -0
  81. package/framework/css/utilities/display.css +257 -0
  82. package/framework/css/utilities/flexbox.css +80 -0
  83. package/framework/css/utilities/grid.css +69 -0
  84. package/framework/css/utilities/icons.css +534 -0
  85. package/framework/css/utilities/lists.css +190 -0
  86. package/framework/css/utilities/spacing.css +167 -0
  87. package/framework/css/utilities/tables.css +81 -0
  88. package/framework/css/utilities/typography.css +159 -0
  89. package/framework/css/utilities/visibility.css +117 -0
  90. package/framework/docs/COURSE_AUTHORING_GUIDE.md +1773 -0
  91. package/framework/docs/COURSE_OUTLINE_GUIDE.md +725 -0
  92. package/framework/docs/COURSE_OUTLINE_TEMPLATE.md +161 -0
  93. package/framework/docs/DATA_MODEL.md +409 -0
  94. package/framework/docs/FRAMEWORK_GUIDE.md +1088 -0
  95. package/framework/docs/USER_GUIDE.md +583 -0
  96. package/framework/docs/examples/cloudflare-channel-relay.js +169 -0
  97. package/framework/docs/examples/cloudflare-data-worker.js +102 -0
  98. package/framework/docs/examples/cloudflare-error-worker.js +228 -0
  99. package/framework/index.html +175 -0
  100. package/framework/js/app/AppActions.js +410 -0
  101. package/framework/js/app/AppState.js +225 -0
  102. package/framework/js/app/AppUI.js +616 -0
  103. package/framework/js/assessment/AssessmentActions.js +615 -0
  104. package/framework/js/assessment/AssessmentFactory.js +471 -0
  105. package/framework/js/assessment/AssessmentState.js +322 -0
  106. package/framework/js/assessment/AssessmentUI.js +451 -0
  107. package/framework/js/automation/api-engagement.js +196 -0
  108. package/framework/js/automation/api-interactions.js +167 -0
  109. package/framework/js/automation/api.js +242 -0
  110. package/framework/js/automation/index.js +41 -0
  111. package/framework/js/components/interactions/drag-drop.js +884 -0
  112. package/framework/js/components/interactions/fill-in.js +535 -0
  113. package/framework/js/components/interactions/hotspot.js +702 -0
  114. package/framework/js/components/interactions/interaction-base.js +511 -0
  115. package/framework/js/components/interactions/likert.js +301 -0
  116. package/framework/js/components/interactions/matching.js +699 -0
  117. package/framework/js/components/interactions/multiple-choice.js +377 -0
  118. package/framework/js/components/interactions/numeric.js +271 -0
  119. package/framework/js/components/interactions/sequencing.js +423 -0
  120. package/framework/js/components/interactions/true-false.js +241 -0
  121. package/framework/js/components/ui-components/accordion.js +442 -0
  122. package/framework/js/components/ui-components/alert.js +88 -0
  123. package/framework/js/components/ui-components/audio-player.js +1193 -0
  124. package/framework/js/components/ui-components/callout.js +121 -0
  125. package/framework/js/components/ui-components/carousel.js +145 -0
  126. package/framework/js/components/ui-components/checkbox-group.js +87 -0
  127. package/framework/js/components/ui-components/checklist.js +40 -0
  128. package/framework/js/components/ui-components/collapse.js +114 -0
  129. package/framework/js/components/ui-components/comparison.js +30 -0
  130. package/framework/js/components/ui-components/conditional-display.js +150 -0
  131. package/framework/js/components/ui-components/content-image.js +41 -0
  132. package/framework/js/components/ui-components/dropdown.js +262 -0
  133. package/framework/js/components/ui-components/embed-frame.js +274 -0
  134. package/framework/js/components/ui-components/features.js +33 -0
  135. package/framework/js/components/ui-components/flip-card.js +230 -0
  136. package/framework/js/components/ui-components/form-validator.js +76 -0
  137. package/framework/js/components/ui-components/hero.js +49 -0
  138. package/framework/js/components/ui-components/index.js +12 -0
  139. package/framework/js/components/ui-components/interactive-image.js +235 -0
  140. package/framework/js/components/ui-components/interactive-timeline.js +285 -0
  141. package/framework/js/components/ui-components/intro-cards.js +35 -0
  142. package/framework/js/components/ui-components/lightbox.js +652 -0
  143. package/framework/js/components/ui-components/modal.js +386 -0
  144. package/framework/js/components/ui-components/notifications.js +145 -0
  145. package/framework/js/components/ui-components/progress.js +88 -0
  146. package/framework/js/components/ui-components/quote.js +41 -0
  147. package/framework/js/components/ui-components/stats.js +33 -0
  148. package/framework/js/components/ui-components/steps.js +41 -0
  149. package/framework/js/components/ui-components/tabs.js +255 -0
  150. package/framework/js/components/ui-components/timeline.js +42 -0
  151. package/framework/js/components/ui-components/toggle-group.js +73 -0
  152. package/framework/js/components/ui-components/tooltip.js +458 -0
  153. package/framework/js/components/ui-components/value-display.js +133 -0
  154. package/framework/js/components/ui-components/video-player.js +686 -0
  155. package/framework/js/core/component-catalog.js +121 -0
  156. package/framework/js/core/event-bus.js +178 -0
  157. package/framework/js/core/interaction-catalog.js +149 -0
  158. package/framework/js/dev/runtime-linter.js +1725 -0
  159. package/framework/js/drivers/cmi5-driver.js +768 -0
  160. package/framework/js/drivers/driver-factory.js +77 -0
  161. package/framework/js/drivers/driver-interface.js +110 -0
  162. package/framework/js/drivers/http-driver-base.js +241 -0
  163. package/framework/js/drivers/lti-driver.js +508 -0
  164. package/framework/js/drivers/proxy-driver.js +444 -0
  165. package/framework/js/drivers/scorm-12-driver.js +560 -0
  166. package/framework/js/drivers/scorm-2004-driver.js +775 -0
  167. package/framework/js/drivers/scorm-driver-base.js +112 -0
  168. package/framework/js/engagement/engagement-manager.js +404 -0
  169. package/framework/js/engagement/engagement-progress.js +191 -0
  170. package/framework/js/engagement/engagement-trackers.js +215 -0
  171. package/framework/js/engagement/requirement-strategies.js +268 -0
  172. package/framework/js/main.js +727 -0
  173. package/framework/js/managers/accessibility-manager.js +499 -0
  174. package/framework/js/managers/assessment-manager.js +230 -0
  175. package/framework/js/managers/audio-manager.js +944 -0
  176. package/framework/js/managers/comment-manager.js +88 -0
  177. package/framework/js/managers/flag-manager.js +86 -0
  178. package/framework/js/managers/interaction-manager.js +254 -0
  179. package/framework/js/managers/interaction-registry.js +96 -0
  180. package/framework/js/managers/objective-manager.js +423 -0
  181. package/framework/js/managers/score-manager.js +441 -0
  182. package/framework/js/managers/video-manager.js +536 -0
  183. package/framework/js/navigation/Breadcrumbs.js +234 -0
  184. package/framework/js/navigation/NavigationActions.js +1132 -0
  185. package/framework/js/navigation/NavigationState.js +276 -0
  186. package/framework/js/navigation/NavigationUI.js +574 -0
  187. package/framework/js/navigation/document-gallery.js +357 -0
  188. package/framework/js/navigation/navigation-helpers.js +175 -0
  189. package/framework/js/navigation/navigation-validators.js +174 -0
  190. package/framework/js/state/index.js +8 -0
  191. package/framework/js/state/lms-connection.js +482 -0
  192. package/framework/js/state/lms-error-utils.js +58 -0
  193. package/framework/js/state/state-commits.js +200 -0
  194. package/framework/js/state/state-domains.js +86 -0
  195. package/framework/js/state/state-manager.js +502 -0
  196. package/framework/js/state/state-validation.js +311 -0
  197. package/framework/js/state/transaction-log.js +41 -0
  198. package/framework/js/state/xapi-statement-service.js +325 -0
  199. package/framework/js/utilities/access-control.js +99 -0
  200. package/framework/js/utilities/breakpoint-manager.js +315 -0
  201. package/framework/js/utilities/canvas-slide.js +35 -0
  202. package/framework/js/utilities/conditional-display.js +388 -0
  203. package/framework/js/utilities/course-channel.js +214 -0
  204. package/framework/js/utilities/course-helpers.js +420 -0
  205. package/framework/js/utilities/data-reporter.js +273 -0
  206. package/framework/js/utilities/error-reporter.js +313 -0
  207. package/framework/js/utilities/hotspot-helper.js +341 -0
  208. package/framework/js/utilities/icons.js +348 -0
  209. package/framework/js/utilities/logger.js +92 -0
  210. package/framework/js/utilities/markdown-renderer.js +45 -0
  211. package/framework/js/utilities/scroll-tracker.js +68 -0
  212. package/framework/js/utilities/ui-initializer.js +146 -0
  213. package/framework/js/utilities/utilities.js +293 -0
  214. package/framework/js/utilities/view-manager.js +227 -0
  215. package/framework/js/validation/html-validators.js +422 -0
  216. package/framework/js/validation/scorm-validators.js +438 -0
  217. package/framework/js/vendor/pipwerks.js +931 -0
  218. package/framework/scripts/generate-narration.js +629 -0
  219. package/framework/scripts/tts-providers/azure-provider.js +178 -0
  220. package/framework/scripts/tts-providers/base-provider.js +81 -0
  221. package/framework/scripts/tts-providers/deepgram-provider.js +135 -0
  222. package/framework/scripts/tts-providers/elevenlabs-provider.js +148 -0
  223. package/framework/scripts/tts-providers/google-provider.js +272 -0
  224. package/framework/scripts/tts-providers/index.js +158 -0
  225. package/framework/scripts/tts-providers/openai-provider.js +143 -0
  226. package/framework/version.json +63 -0
  227. package/lib/authoring-api.js +919 -0
  228. package/lib/build-linter.js +450 -0
  229. package/lib/build-packaging.js +186 -0
  230. package/lib/build.js +88 -0
  231. package/lib/cloud.js +691 -0
  232. package/lib/convert.js +341 -0
  233. package/lib/course-parser.js +936 -0
  234. package/lib/course-writer.js +258 -0
  235. package/lib/create.js +248 -0
  236. package/lib/css-index.js +237 -0
  237. package/lib/dev.js +51 -0
  238. package/lib/export-content.js +1246 -0
  239. package/lib/headless-browser.js +413 -0
  240. package/lib/import.js +377 -0
  241. package/lib/index.js +80 -0
  242. package/lib/info.js +79 -0
  243. package/lib/interaction-formatters.js +568 -0
  244. package/lib/manifest/cmi5-manifest.js +63 -0
  245. package/lib/manifest/lti-tool-config.js +53 -0
  246. package/lib/manifest/manifest-factory.js +99 -0
  247. package/lib/manifest/scorm-12-manifest.js +61 -0
  248. package/lib/manifest/scorm-2004-manifest.js +94 -0
  249. package/lib/manifest/scorm-proxy-manifest.js +104 -0
  250. package/lib/manifest-parser.js +96 -0
  251. package/lib/mcp-prompts.js +753 -0
  252. package/lib/mcp-server.js +316 -0
  253. package/lib/narration.js +53 -0
  254. package/lib/pdf-structure.js +142 -0
  255. package/lib/preview-export.js +231 -0
  256. package/lib/preview-routes-api.js +662 -0
  257. package/lib/preview-routes-editing.js +159 -0
  258. package/lib/preview-routes-lms.js +230 -0
  259. package/lib/preview-server.js +564 -0
  260. package/lib/project-utils.js +269 -0
  261. package/lib/proxy-templates/proxy.html +68 -0
  262. package/lib/proxy-templates/scorm-bridge.js +112 -0
  263. package/lib/scaffold.js +193 -0
  264. package/lib/schema-extractor.js +361 -0
  265. package/lib/slide-source-editor.js +586 -0
  266. package/lib/stub-player/app-viewer.js +195 -0
  267. package/lib/stub-player/app.js +370 -0
  268. package/lib/stub-player/catalog-panel.js +312 -0
  269. package/lib/stub-player/config-panel.js +1303 -0
  270. package/lib/stub-player/content-generator.js +586 -0
  271. package/lib/stub-player/content-viewer.js +173 -0
  272. package/lib/stub-player/debug-panel.js +420 -0
  273. package/lib/stub-player/edit-mode.js +922 -0
  274. package/lib/stub-player/edit-utils.js +400 -0
  275. package/lib/stub-player/header-bar.js +354 -0
  276. package/lib/stub-player/interaction-editor.js +210 -0
  277. package/lib/stub-player/interactions-panel.js +565 -0
  278. package/lib/stub-player/lms-api.js +1094 -0
  279. package/lib/stub-player/login-screen.js +74 -0
  280. package/lib/stub-player/outline-mode.js +689 -0
  281. package/lib/stub-player/styles/_assessments-panel.css +245 -0
  282. package/lib/stub-player/styles/_base.css +89 -0
  283. package/lib/stub-player/styles/_catalog-icons.css +96 -0
  284. package/lib/stub-player/styles/_catalog-panel.css +291 -0
  285. package/lib/stub-player/styles/_config-panel.css +636 -0
  286. package/lib/stub-player/styles/_content-viewer.css +834 -0
  287. package/lib/stub-player/styles/_debug-panel.css +576 -0
  288. package/lib/stub-player/styles/_edit-mode.css +128 -0
  289. package/lib/stub-player/styles/_header-bar.css +343 -0
  290. package/lib/stub-player/styles/_interaction-editor.css +140 -0
  291. package/lib/stub-player/styles/_interactions-panel.css +1038 -0
  292. package/lib/stub-player/styles/_login-screen.css +102 -0
  293. package/lib/stub-player/styles/_outline-mode.css +752 -0
  294. package/lib/stub-player/styles.css +15 -0
  295. package/lib/stub-player.js +160 -0
  296. package/lib/test-data-reporting.js +176 -0
  297. package/lib/test-error-reporting.js +146 -0
  298. package/lib/token.js +86 -0
  299. package/lib/upgrade.js +257 -0
  300. package/lib/validation-rules.js +517 -0
  301. package/lib/vite-plugin-content-discovery.js +296 -0
  302. package/package.json +108 -0
  303. package/schemas/XMLSchema.dtd +402 -0
  304. package/schemas/adlcp_v1p3.xsd +111 -0
  305. package/schemas/adlnav_v1p3.xsd +61 -0
  306. package/schemas/adlseq_v1p3.xsd +93 -0
  307. package/schemas/common/anyElement.xsd +27 -0
  308. package/schemas/common/dataTypes.xsd +138 -0
  309. package/schemas/common/elementNames.xsd +767 -0
  310. package/schemas/common/elementTypes.xsd +786 -0
  311. package/schemas/common/rootElement.xsd +31 -0
  312. package/schemas/common/vocabTypes.xsd +345 -0
  313. package/schemas/common/vocabValues.xsd +257 -0
  314. package/schemas/datatypes.dtd +203 -0
  315. package/schemas/ims_xml.xsd +35 -0
  316. package/schemas/imscp_v1p1.xsd +368 -0
  317. package/schemas/imsss_v1p0.xsd +67 -0
  318. package/schemas/imsss_v1p0auxresource.xsd +19 -0
  319. package/schemas/imsss_v1p0control.xsd +20 -0
  320. package/schemas/imsss_v1p0delivery.xsd +17 -0
  321. package/schemas/imsss_v1p0limit.xsd +47 -0
  322. package/schemas/imsss_v1p0objective.xsd +67 -0
  323. package/schemas/imsss_v1p0random.xsd +16 -0
  324. package/schemas/imsss_v1p0rollup.xsd +46 -0
  325. package/schemas/imsss_v1p0seqrule.xsd +108 -0
  326. package/schemas/imsss_v1p0util.xsd +94 -0
  327. package/schemas/license.txt +17 -0
  328. package/schemas/lom.xsd +102 -0
  329. package/schemas/lomCustom.xsd +62 -0
  330. package/schemas/lomLoose.xsd +62 -0
  331. package/schemas/lomStrict.xsd +62 -0
  332. package/schemas/xml.xsd +81 -0
  333. package/template/.env.example +92 -0
  334. package/template/course/assets/audio/example-intro.mp3 +0 -0
  335. package/template/course/assets/audio/example-ui-demo--compact-player.mp3 +0 -0
  336. package/template/course/assets/audio/example-ui-demo--demo-modal.mp3 +0 -0
  337. package/template/course/assets/audio/example-ui-demo--full-player.mp3 +0 -0
  338. package/template/course/assets/docs/example_md_1.md +39 -0
  339. package/template/course/assets/docs/example_md_2.md +41 -0
  340. package/template/course/assets/docs/example_pdf_1_thumbnail.png +0 -0
  341. package/template/course/assets/docs/example_pdf_2.pdf +0 -0
  342. package/template/course/assets/images/course-architecture.svg +36 -0
  343. package/template/course/assets/images/logo.svg +14 -0
  344. package/template/course/assets/widgets/counter-demo.html +190 -0
  345. package/template/course/assets/widgets/gravity-painter.html +384 -0
  346. package/template/course/course-config.js +539 -0
  347. package/template/course/icons.js +19 -0
  348. package/template/course/interactions/PLUGIN_GUIDE.md +97 -0
  349. package/template/course/slides/example-course-structure.js +138 -0
  350. package/template/course/slides/example-final-exam.js +144 -0
  351. package/template/course/slides/example-finishing.js +127 -0
  352. package/template/course/slides/example-interactions-showcase.js +615 -0
  353. package/template/course/slides/example-preview-tour.js +129 -0
  354. package/template/course/slides/example-remedial.js +143 -0
  355. package/template/course/slides/example-summary.js +103 -0
  356. package/template/course/slides/example-ui-showcase.js +1805 -0
  357. package/template/course/slides/example-welcome.js +123 -0
  358. package/template/course/slides/example-workflow.js +140 -0
  359. package/template/course/theme.css +165 -0
  360. package/template/eslint.config.js +47 -0
  361. package/template/package.json +28 -0
  362. package/template/vite.config.js +339 -0
@@ -0,0 +1,539 @@
1
+ /**
2
+ * course-config.js — Centralized course configuration for CourseCode
3
+ * Single source of truth: all metadata, structure, objectives, and feature configuration
4
+ *
5
+ * SCHEMA REFERENCE (for AI agents authoring courses)
6
+ *
7
+ * LAYOUT: 'article' (default) | 'traditional' | 'focused' | 'presentation' | 'canvas'
8
+ *
9
+ * SCORING (null = disabled):
10
+ * { type: 'average'|'weighted'|'maximum'|'custom', sources: [...], calculate?: fn }
11
+ *
12
+ * OBJECTIVES (auto-managed by criteria OR manual via assessment.assessmentObjective):
13
+ * { id: 'obj-X', description: 'text', criteria: {type, ...fields}, initialCompletion: 'incomplete'|'completed', initialSuccess: 'unknown'|'passed'|'failed' }
14
+ * Criteria types: slideVisited|allSlidesVisited|timeOnSlide|flag|allFlags
15
+ *
16
+ * AUDIO (slide-level narration - playback settings only):
17
+ * { src: 'audio/narration.mp3', autoplay: false, completionThreshold: 0.95 }
18
+ * - src: path relative to course/assets/ (or full path/URL)
19
+ * - autoplay: whether to start playing when slide loads (default: false)
20
+ * - completionThreshold: percentage (0-1) of audio that must be heard for completion (default: 0.95)
21
+ * To gate navigation on audio, use engagement requirement: { type: 'slideAudioComplete' }
22
+ *
23
+ * NARRATION SOURCE TYPES:
24
+ * Slide export: { src: '@slides/intro.js' } → course/assets/audio/intro.mp3
25
+ * Modal/Tab audio: { src: '@slides/intro.js#key' } → course/assets/audio/intro--key.mp3
26
+ * Direct file: { src: 'audio/custom.mp3' } → course/assets/audio/custom.mp3
27
+ *
28
+ * MULTI-KEY NARRATION (in slide file):
29
+ * export const narration = {
30
+ * slide: `Main slide narration...`,
31
+ * 'about-modal': `Narration when modal opens...`,
32
+ * 'details-tab': `Narration when tab is selected...`,
33
+ * voice_id: 'optional-voice-id' // Optional: voice settings apply to all
34
+ * };
35
+ * Generates: intro.mp3, intro--about-modal.mp3, intro--details-tab.mp3
36
+ *
37
+ * TAB AUDIO (per-panel audio on tabs):
38
+ * <div class="tabs-panel" data-audio-src="audio/tab1.mp3" data-audio-required="true" data-audio-threshold="0.9">
39
+ * - Audio loads when tab is activated
40
+ * - If required, tab isn't marked "viewed" until audio threshold is reached
41
+ *
42
+ * MODAL AUDIO (audio triggered by modal):
43
+ * <button data-modal-trigger="..." data-audio-src="audio/modal.mp3" data-audio-required="true" data-audio-threshold="0.9">
44
+ * OR programmatically: Modal.show({ audio: { src, required, completionThreshold } })
45
+ *
46
+ * ENGAGEMENT (required: false = no tracking):
47
+ * requirements: [{ type: viewAllTabs|viewAllPanels|viewAllFlipCards|viewAllHotspots|interactionComplete|allInteractionsComplete|scrollDepth|timeOnSlide|flag|allFlags|slideAudioComplete|audioComplete|modalAudioComplete, message?: str, ...props }]
48
+ * Audio requirement types:
49
+ * - slideAudioComplete: slide-level audio (no props needed)
50
+ * - audioComplete: standalone audio player (requires audioId)
51
+ * - modalAudioComplete: modal audio (requires modalId)
52
+ * Engagement requirement properties: interactionId, label (for interactionComplete), percentage (scrollDepth), minSeconds (timeOnSlide), key|flags (flag/allFlags), equals (flag matching)
53
+ * Flip card tracking: Each flip card must have data-flip-card-id attribute for viewAllFlipCards to work
54
+ *
55
+ * NAVIGATION.GATING.CONDITIONS:
56
+ * objectiveStatus: {objectiveId, completion_status?|success_status?} | assessmentStatus: {assessmentId, requires: 'passed'|'failed'} | timeOnSlide: {slideId, minSeconds} | flag: {key, equals?} | custom: {key, equals?}
57
+ *
58
+ * WINDOW AUTO-RESIZE (environment.autoResizeWindow):
59
+ * { width: 1024, height: 768 } - Resize popup window to these dimensions on load
60
+ * true - Use default size (1024x768)
61
+ * false - Disable auto-resize entirely
62
+ * Note: Only works for popup windows. Browsers block resize for main windows.
63
+ *
64
+ * SUPPORT (error modal contact info):
65
+ * { email: 'support@example.com', phone?: '+1-800-555-0100' }
66
+ * Displayed in error modals when users encounter issues that may affect progress.
67
+ *
68
+ * ERROR REPORTING (environment.errorReporting):
69
+ * { endpoint: 'https://your-worker.workers.dev/errors', includeContext?: true, enableUserReports?: true }
70
+ * Sends framework errors to a webhook for email alerts. Disabled if endpoint is missing.
71
+ * enableUserReports adds "Report Issue" button to settings menu (default: true when endpoint set).
72
+ * Use with Cloudflare Worker to keep API keys server-side.
73
+ *
74
+ * LMS COMPATIBILITY PROFILE (environment.lmsCompatibilityMode):
75
+ * 'auto' (default): choose profile by format (strict-scorm12 / conservative-scorm2004 / modern-http)
76
+ * 'balanced': generic safe defaults
77
+ * 'strict-scorm12': conservative timeouts for legacy SCORM 1.2 LMS behavior
78
+ * 'conservative-scorm2004': conservative timeouts for SCORM 2004 LMS behavior
79
+ * 'modern-http': tuned for cmi5/LTI HTTP-based flows
80
+ *
81
+ * SLIDE: { type: 'slide', id, component, title, menu, engagement, navigation, audio? }
82
+ * ASSESSMENT: { type: 'assessment', id, component, menu, engagement, navigation } + assessmentObjective in component
83
+ * SECTION: { type: 'section', id, menu, children: [] }
84
+ *
85
+ * navigation.controls: { exitTarget?: slideId, nextTarget?: slideId, previousTarget?: slideId }
86
+ * navigation.sequence: { includeByDefault: bool, includeWhen: condition?, insert: {position: 'before'|'after', slideId} }
87
+ * navigation.breadcrumbs: { enabled: bool } // Show breadcrumb path in slide area (hidden when sidebar open)
88
+ * menu: { label: str, icon?: emoji, hidden?: bool, defaultExpanded?: bool }
89
+ *
90
+ * EXTERNAL HOSTING (CDN deployment with proxy packages):
91
+ * format: 'scorm1.2-proxy' | 'scorm2004-proxy' | 'cmi5-remote'
92
+ * externalUrl: 'https://cdn.example.com/courses/my-course' // Where course is hosted
93
+ * accessControl: {
94
+ * clients: {
95
+ * 'acme-corp': { token: 'generated-token-here' },
96
+ * 'globex': { token: 'another-token-here' }
97
+ * }
98
+ * }
99
+ * Generate tokens: coursecode token --add <clientId>
100
+ * Build output: One package per client (e.g., acme-corp_proxy.zip)
101
+ *
102
+ * CLOUD DEPLOYMENT:
103
+ * When using CourseCode Cloud, the format setting is ignored. The cloud generates
104
+ * any LMS format on demand from the universal build — no rebuild needed.
105
+ * Authors deploying to the cloud do not need to set a format here.
106
+ *
107
+ * NAVIGATION.HEADER:
108
+ * { enabled: bool } // Show/hide course header bar. Canvas layout hides by default.
109
+ *
110
+ * NAVIGATION.SIDEBAR:
111
+ * { enabled: bool, position: 'left'|'right', width: CSS, collapsible: bool, defaultCollapsed: bool, showProgress: bool }
112
+ *
113
+ * NAVIGATION.FOOTER:
114
+ * { showButtons: bool } // Show/hide prev/next nav buttons. Traditional layout always shows.
115
+ *
116
+ * NAVIGATION.DOCUMENT_GALLERY:
117
+ * { enabled: bool, directory: 'assets/docs', label: str, icon: iconName, allowDownloads: bool, fileTypes: ['pdf','md',...] }
118
+ *
119
+ * SLIDE_DEFAULTS:
120
+ * { contentWidth: 'narrow'|'medium'|'wide'|'full' } // Auto-wraps slide content; per-slide override via data-content-width attr
121
+ *
122
+ * ENVIRONMENT.DEVELOPMENT:
123
+ * { disableGating: bool, showSlideIndicator: bool } // disableGating bypasses all navigation gating during dev
124
+ */
125
+
126
+ export const courseConfig = {
127
+ metadata: {
128
+ title: 'CourseCode',
129
+ description: 'CourseCode template for course development',
130
+ version: '2.0.0',
131
+ author: 'Seth Vincent',
132
+ language: 'en'
133
+ },
134
+ layout: 'article',
135
+ branding: {
136
+ logo: './course/assets/images/logo.svg',
137
+ logoAlt: 'CourseCode Logo',
138
+ companyName: 'CourseCode',
139
+ courseTitle: 'CourseCode'
140
+ },
141
+ support: {
142
+ email: 'support@example.com'
143
+ },
144
+ scoring: {
145
+ type: 'average',
146
+ sources: [
147
+ 'assessment:example-final-exam'
148
+ ]
149
+ },
150
+ objectives: [
151
+ {
152
+ id: 'visited-finishing',
153
+ description: 'View the finishing slide',
154
+ initialCompletion: 'incomplete',
155
+ initialSuccess: 'unknown',
156
+ criteria: {
157
+ type: 'slideVisited',
158
+ slideId: 'example-finishing'
159
+ }
160
+ },
161
+ {
162
+ id: 'core-content',
163
+ description: 'Visit all core content slides',
164
+ initialCompletion: 'incomplete',
165
+ initialSuccess: 'unknown',
166
+ criteria: {
167
+ type: 'allSlidesVisited',
168
+ slideIds: [
169
+ 'example-interactions-showcase',
170
+ 'example-ui-showcase'
171
+ ]
172
+ }
173
+ },
174
+ {
175
+ id: 'thorough-review',
176
+ description: 'Spend at least 2 minutes reviewing content',
177
+ initialCompletion: 'incomplete',
178
+ initialSuccess: 'unknown',
179
+ criteria: {
180
+ type: 'timeOnSlide',
181
+ slideId: 'example-interactions-showcase',
182
+ minSeconds: 120
183
+ }
184
+ },
185
+ {
186
+ id: 'custom-mastery',
187
+ description: 'Demonstrate mastery (custom logic)',
188
+ initialCompletion: 'incomplete',
189
+ initialSuccess: 'unknown'
190
+ },
191
+ {
192
+ id: 'example-intro-completed-flag',
193
+ description: 'Complete introduction (flag-based)',
194
+ initialCompletion: 'incomplete',
195
+ initialSuccess: 'unknown',
196
+ criteria: {
197
+ type: 'flag',
198
+ key: 'example-intro-complete',
199
+ equals: true
200
+ }
201
+ },
202
+ {
203
+ id: 'all-sections-unlocked',
204
+ description: 'Unlock all course sections',
205
+ initialCompletion: 'incomplete',
206
+ initialSuccess: 'unknown',
207
+ criteria: {
208
+ type: 'allFlags',
209
+ flags: [
210
+ 'section-1-unlocked',
211
+ 'section-2-unlocked',
212
+ {
213
+ key: 'section-3-unlocked',
214
+ equals: true
215
+ }
216
+ ]
217
+ }
218
+ }
219
+ ],
220
+ structure: [
221
+ {
222
+ type: 'section',
223
+ id: 'example-getting-started',
224
+ menu: {
225
+ label: 'Getting Started',
226
+ icon: 'rocket',
227
+ defaultExpanded: true
228
+ },
229
+ children: [
230
+ {
231
+ type: 'slide',
232
+ id: 'example-welcome',
233
+ component: '@slides/example-welcome.js',
234
+ title: 'Welcome',
235
+ menu: {
236
+ label: 'Welcome',
237
+ icon: 'home'
238
+ },
239
+ engagement: {
240
+ required: false
241
+ },
242
+ navigation: {
243
+ sequential: true,
244
+ controls: {
245
+ showPrevious: false,
246
+ showNext: true
247
+ }
248
+ }
249
+ },
250
+ {
251
+ type: 'slide',
252
+ id: 'example-workflow',
253
+ component: '@slides/example-workflow.js',
254
+ title: 'The AI Workflow',
255
+ menu: {
256
+ label: 'AI Workflow',
257
+ icon: 'zap'
258
+ },
259
+ engagement: {
260
+ required: false
261
+ },
262
+ navigation: {
263
+ sequential: true
264
+ }
265
+ },
266
+ {
267
+ type: 'slide',
268
+ id: 'example-preview-tour',
269
+ component: '@slides/example-preview-tour.js',
270
+ title: 'Using the Preview',
271
+ menu: {
272
+ label: 'Preview Tour',
273
+ icon: 'eye'
274
+ },
275
+ engagement: {
276
+ required: false
277
+ },
278
+ navigation: {
279
+ sequential: true
280
+ }
281
+ }
282
+ ]
283
+ },
284
+ {
285
+ type: 'section',
286
+ id: 'example-building-courses',
287
+ menu: {
288
+ label: 'Building Courses',
289
+ icon: 'folder',
290
+ defaultExpanded: true
291
+ },
292
+ children: [
293
+ {
294
+ type: 'slide',
295
+ id: 'example-course-structure',
296
+ component: '@slides/example-course-structure.js',
297
+ title: 'Your Course Files',
298
+ menu: {
299
+ label: 'Course Files',
300
+ icon: 'folder-open'
301
+ },
302
+ engagement: {
303
+ required: false
304
+ },
305
+ navigation: {
306
+ sequential: true
307
+ }
308
+ },
309
+ {
310
+ type: 'slide',
311
+ id: 'example-ui-showcase',
312
+ component: '@slides/example-ui-showcase.js',
313
+ title: 'UI Components Showcase',
314
+ menu: {
315
+ label: 'UI Components',
316
+ icon: 'layout'
317
+ },
318
+ engagement: {
319
+ required: false
320
+ },
321
+ navigation: {
322
+ sequential: true
323
+ }
324
+ },
325
+ {
326
+ type: 'slide',
327
+ id: 'example-interactions-showcase',
328
+ component: '@slides/example-interactions-showcase.js',
329
+ title: 'Interactions Showcase',
330
+ menu: {
331
+ label: 'Interactions',
332
+ icon: 'mouse-pointer'
333
+ },
334
+ engagement: {
335
+ required: true,
336
+ mode: 'all',
337
+ requirements: [
338
+ {
339
+ type: 'viewAllTabs'
340
+ },
341
+ {
342
+ type: 'interactionComplete',
343
+ interactionId: 'system-architecture-dd'
344
+ },
345
+ {
346
+ type: 'interactionComplete',
347
+ interactionId: 'lms-standards-matching'
348
+ },
349
+ {
350
+ type: 'interactionComplete',
351
+ interactionId: 'lms-standards-text'
352
+ },
353
+ {
354
+ type: 'interactionComplete',
355
+ interactionId: 'requirements-spec-fillin'
356
+ },
357
+ {
358
+ type: 'interactionComplete',
359
+ interactionId: 'efficiency-calculation'
360
+ },
361
+ {
362
+ type: 'interactionComplete',
363
+ interactionId: 'framework-components-qa'
364
+ }
365
+ ],
366
+ showIndicator: true
367
+ },
368
+ navigation: {
369
+ sequential: true
370
+ }
371
+ },
372
+ {
373
+ type: 'slide',
374
+ id: 'example-finishing',
375
+ component: '@slides/example-finishing.js',
376
+ title: 'Finishing Your Course',
377
+ menu: {
378
+ label: 'Finishing',
379
+ icon: 'flag'
380
+ },
381
+ engagement: {
382
+ required: false
383
+ },
384
+ navigation: {
385
+ sequential: true
386
+ }
387
+ }
388
+ ]
389
+ },
390
+ {
391
+ type: 'assessment',
392
+ id: 'example-final-exam',
393
+ component: '@slides/example-final-exam.js',
394
+ title: 'Knowledge Check',
395
+ menu: {
396
+ label: 'Knowledge Check',
397
+ icon: 'clipboard-check'
398
+ },
399
+ engagement: {
400
+ required: false
401
+ },
402
+ navigation: {
403
+ sequential: true,
404
+ gating: {
405
+ mode: 'all',
406
+ message: 'Complete all slides before starting the knowledge check.',
407
+ conditions: [
408
+ {
409
+ type: 'objectiveStatus',
410
+ objectiveId: 'visited-finishing',
411
+ completion_status: 'completed'
412
+ }
413
+ ]
414
+ }
415
+ }
416
+ },
417
+ {
418
+ type: 'slide',
419
+ id: 'example-remedial',
420
+ component: '@slides/example-remedial.js',
421
+ title: 'Review Content',
422
+ menu: {
423
+ hidden: true
424
+ },
425
+ engagement: {
426
+ required: false
427
+ },
428
+ navigation: {
429
+ controls: {
430
+ exitTarget: 'example-final-exam'
431
+ },
432
+ gating: {
433
+ mode: 'any',
434
+ message: 'Review content is available after an unsuccessful assessment attempt.',
435
+ conditions: [
436
+ {
437
+ type: 'assessmentStatus',
438
+ assessmentId: 'example-final-exam',
439
+ requires: 'failed'
440
+ }
441
+ ]
442
+ }
443
+ }
444
+ },
445
+ {
446
+ type: 'slide',
447
+ id: 'example-summary',
448
+ component: '@slides/example-summary.js',
449
+ title: 'Course Complete',
450
+ menu: {
451
+ label: 'Complete',
452
+ icon: 'award'
453
+ },
454
+ engagement: {
455
+ required: false
456
+ },
457
+ navigation: {
458
+ sequential: true,
459
+ gating: {
460
+ mode: 'all',
461
+ message: 'Complete the knowledge check to see the summary.',
462
+ conditions: [
463
+ {
464
+ type: 'assessmentStatus',
465
+ assessmentId: 'example-final-exam',
466
+ requires: 'passed'
467
+ }
468
+ ]
469
+ }
470
+ }
471
+ }
472
+ ],
473
+ navigation: {
474
+ header: {
475
+ enabled: true
476
+ },
477
+ footer: {
478
+ showButtons: true
479
+ },
480
+ sidebar: {
481
+ enabled: true,
482
+ position: 'left',
483
+ width: '280px',
484
+ collapsible: true,
485
+ defaultCollapsed: true,
486
+ showProgress: true
487
+ },
488
+ breadcrumbs: {
489
+ enabled: true
490
+ },
491
+ documentGallery: {
492
+ enabled: true,
493
+ directory: 'assets/docs',
494
+ label: 'Resources',
495
+ icon: 'file-text',
496
+ allowDownloads: true,
497
+ fileTypes: [
498
+ 'pdf',
499
+ 'md',
500
+ 'jpg',
501
+ 'png'
502
+ ]
503
+ }
504
+ },
505
+ features: {
506
+ accessibility: {
507
+ darkMode: true,
508
+ fontSize: true,
509
+ highContrast: true,
510
+ reducedMotion: true,
511
+ keyboardShortcuts: true
512
+ },
513
+ security: false,
514
+ offline: false,
515
+ analytics: true,
516
+ feedback: true
517
+ },
518
+ completion: {
519
+ promptForComments: true,
520
+ promptForRating: true
521
+ },
522
+ slideDefaults: {
523
+ contentWidth: 'medium'
524
+ },
525
+ environment: {
526
+ lmsCompatibilityMode: 'auto',
527
+ autoResizeWindow: false,
528
+ disableBeforeUnloadGuard: true,
529
+ development: {
530
+ disableGating: false,
531
+ showSlideIndicator: true
532
+ },
533
+ automation: {
534
+ enabled: true,
535
+ disableBeforeUnloadGuard: true,
536
+ exposeCorrectAnswers: true
537
+ }
538
+ }
539
+ };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @file icons.js
3
+ * @description Custom icon definitions for the course.
4
+ *
5
+ * Add any custom SVG icons here to be used in your course configuration.
6
+ * Keys defined here can be used in course-config.js (e.g., menu: { icon: 'my-custom-icon' }).
7
+ *
8
+ * Format:
9
+ * export const customIcons = {
10
+ * 'my-icon': '<path d="..." />', // Inner SVG content
11
+ * 'another-icon': '<svg>...</svg>' // Full SVG string
12
+ * };
13
+ */
14
+
15
+ export const customIcons = {
16
+ // Add custom icons here
17
+ // Example:
18
+ // 'rocket': '<path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.48-.56.93-1.23 1.4-2l-4.4-4.4c-.77.47-1.44.92-2 1.4z"/><path d="m12 15-3-3"/><path d="m15 12-3-3"/><path d="M8 8l9-9 9 9-9 9-9-9z"/>'
19
+ };
@@ -0,0 +1,97 @@
1
+ # Custom Interactions
2
+
3
+ Drop a `.js` file here to auto-register a custom interaction type.
4
+
5
+ ## Quick Start
6
+
7
+ **File:** `rating-scale.js` → **Factory:** `CourseCode.createRatingScaleQuestion()`
8
+
9
+ ```javascript
10
+ // Optional: Schema for linting/AI assistance
11
+ export const schema = {
12
+ type: 'rating-scale',
13
+ properties: {
14
+ options: { type: 'array', required: true, description: 'Rating options' },
15
+ correctAnswer: { type: 'string', description: 'Correct option index' }
16
+ }
17
+ };
18
+
19
+ // Optional: Metadata for UI tools
20
+ export const metadata = {
21
+ label: 'Rating Scale',
22
+ category: 'interactive',
23
+ scormType: 'choice'
24
+ };
25
+
26
+ // Required: Creator function
27
+ export function create(container, config) {
28
+ let response = null;
29
+
30
+ // Inject styles once
31
+ if (!document.getElementById('rating-scale-styles')) {
32
+ const el = document.createElement('style');
33
+ el.id = 'rating-scale-styles';
34
+ el.textContent = `
35
+ .rating-scale { display: flex; gap: 0.5rem; }
36
+ .rating-scale-option { cursor: pointer; padding: 0.5rem 1rem; border: 1px solid var(--border); border-radius: var(--radius); }
37
+ .rating-scale-option.selected { background: var(--primary); color: white; }
38
+ `;
39
+ document.head.appendChild(el);
40
+ }
41
+
42
+ container.innerHTML = `
43
+ <div class="interaction" data-interaction-id="${config.id}">
44
+ <p class="prompt">${config.prompt}</p>
45
+ <div class="rating-scale">
46
+ ${config.options.map((opt, i) =>
47
+ `<button type="button" class="rating-scale-option" data-value="${i}">${opt}</button>`
48
+ ).join('')}
49
+ </div>
50
+ </div>
51
+ `;
52
+
53
+ container.querySelectorAll('.rating-scale-option').forEach(btn => {
54
+ btn.addEventListener('click', () => {
55
+ container.querySelectorAll('.rating-scale-option').forEach(b => b.classList.remove('selected'));
56
+ btn.classList.add('selected');
57
+ response = btn.dataset.value;
58
+ });
59
+ });
60
+
61
+ return {
62
+ getResponse: () => response,
63
+ setResponse: (val) => {
64
+ response = val;
65
+ container.querySelectorAll('.rating-scale-option').forEach(btn => {
66
+ btn.classList.toggle('selected', btn.dataset.value === String(val));
67
+ });
68
+ },
69
+ checkAnswer: () => ({ correct: response === config.correctAnswer, score: response === config.correctAnswer ? 1 : 0 }),
70
+ reset: () => {
71
+ response = null;
72
+ container.querySelectorAll('.rating-scale-option').forEach(b => b.classList.remove('selected'));
73
+ }
74
+ };
75
+ }
76
+ ```
77
+
78
+ ## Exports
79
+
80
+ | Export | Required | Purpose |
81
+ |--------|----------|---------|
82
+ | `create(container, config)` | ✅ | Factory function |
83
+ | `schema` | Optional | Enables linting, AI assistance, preview editor |
84
+ | `metadata` | Optional | UI labels, categories, SCORM interaction type |
85
+
86
+ ## Usage in Slides
87
+
88
+ ```javascript
89
+ const rating = CourseCode.createRatingScaleQuestion(container, {
90
+ id: 'my-rating',
91
+ prompt: 'How would you rate this?',
92
+ options: ['Poor', 'Fair', 'Good', 'Excellent'],
93
+ correctAnswer: '3'
94
+ });
95
+ ```
96
+
97
+ See `COURSE_AUTHORING_GUIDE.md` for full interaction API.