coursecode 0.1.0 → 0.1.2
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.
- package/README.md +40 -22
- package/framework/docs/FRAMEWORK_GUIDE.md +6 -7
- package/lib/build-packaging.d.ts +33 -0
- package/lib/build-packaging.js +20 -13
- package/lib/index.d.ts +52 -0
- package/lib/index.js +1 -0
- package/lib/manifest/manifest-factory.d.ts +10 -0
- package/lib/stub-player.d.ts +15 -0
- package/package.json +17 -7
package/README.md
CHANGED
|
@@ -6,18 +6,20 @@ Drop in your existing PDFs, Word docs, or PowerPoints — AI converts them into
|
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
9
|
+
- **MCP integration**: AI connects directly to your course — previews, screenshots, linting, and testing without manual file sharing
|
|
10
|
+
- **Full LMS integration**: SCORM 1.2, SCORM 2004, cmi5, and LTI with complete tracking records
|
|
11
|
+
- **AI-ready authoring**: Structured guides and MCP tools for AI-assisted course development
|
|
12
|
+
- **Rich UI components**: Images, video, accordions, tabs, and custom sandboxed HTML/JS embeds
|
|
13
|
+
- **Rich interactions**: Multiple choice, drag-drop, fill-in-the-blank, matching, sequencing, and more
|
|
14
|
+
- **Fully accessible**: WCAG 2.1 AA compliant with dark mode, high contrast, and reduced motion
|
|
15
|
+
- **TTS audio narration**: Built-in player with AI text-to-speech generation (ElevenLabs, Deepgram, Google, BYO API Key)
|
|
16
|
+
- **Smart tracking**: Engagement requirements, learning objectives, and progress persistence
|
|
17
|
+
- **Themeable design**: CSS custom properties for easy brand customization
|
|
18
|
+
- **Custom endpoints**: Optional webhooks for error reporting and learning record storage
|
|
19
|
+
- **Drop-in content conversion**: Feed existing PDFs, Word docs, or PowerPoint files to AI and get a complete, interactive course
|
|
20
|
+
- **Live preview**: Visual editing, status dashboard, config panels, catalog browser, and full LMS simulation with debug tools
|
|
21
|
+
- **[CourseCode Cloud](https://www.coursecodecloud.com)** *(coming soon)*: Deploy from CLI, share preview links, download any LMS format on demand — no rebuilds
|
|
22
|
+
- **CourseCode Desktop** *(coming soon)*: Native app for Mac and Windows with AI-assisted editing, built-in preview, and no code required
|
|
21
23
|
|
|
22
24
|
---
|
|
23
25
|
|
|
@@ -55,7 +57,7 @@ Open `http://localhost:4173` to view and edit your course.
|
|
|
55
57
|
|
|
56
58
|
The example course included with every new project is a complete guide to using CourseCode.
|
|
57
59
|
|
|
58
|
-
|
|
60
|
+
**New to CourseCode?** Read the [User Guide](framework/docs/USER_GUIDE.md) for step-by-step instructions.
|
|
59
61
|
|
|
60
62
|
---
|
|
61
63
|
|
|
@@ -93,8 +95,8 @@ my-course/
|
|
|
93
95
|
│ ├── assets/ # Images, audio, video
|
|
94
96
|
│ │ ├── images/
|
|
95
97
|
│ │ └── audio/
|
|
96
|
-
│
|
|
97
|
-
|
|
98
|
+
│ └── theme.css # Brand customization
|
|
99
|
+
│
|
|
98
100
|
├── framework/ # Framework code (don't edit)
|
|
99
101
|
│ └── docs/ # Guides and templates
|
|
100
102
|
```
|
|
@@ -114,11 +116,11 @@ All guides are in `framework/docs/`:
|
|
|
114
116
|
|
|
115
117
|
| Document | Audience | Purpose |
|
|
116
118
|
|----------|----------|---------|
|
|
117
|
-
| `README.md` | Humans | Project overview and getting started |
|
|
118
119
|
| `USER_GUIDE.md` | Humans | Complete guide — workflows, features, deployment |
|
|
119
120
|
| `COURSE_AUTHORING_GUIDE.md` | AI Agents | Slide authoring, interactions, CSS styling |
|
|
120
121
|
| `COURSE_OUTLINE_GUIDE.md` | AI Agents | How to write effective course outlines |
|
|
121
122
|
| `COURSE_OUTLINE_TEMPLATE.md` | AI Agents | Blank template to start an outline |
|
|
123
|
+
| `DATA_MODEL.md` | AI Agents | LMS data model and tracking fields |
|
|
122
124
|
| `FRAMEWORK_GUIDE.md` | AI Agents | Framework internals (advanced) |
|
|
123
125
|
|
|
124
126
|
---
|
|
@@ -167,22 +169,26 @@ The preview server provides:
|
|
|
167
169
|
- **Component catalog**: Browse available UI elements with live previews
|
|
168
170
|
- **Debug tools**: Inspect LMS state, test interactions, verify tracking
|
|
169
171
|
|
|
170
|
-
When ready,
|
|
172
|
+
When ready, deploy:
|
|
173
|
+
|
|
174
|
+
**With [CourseCode Cloud](https://www.coursecodecloud.com)** *(coming soon)*: Push your course and get a live link. Cloud handles hosting, generates any LMS format on demand, and gives you sharable preview links with optional password protection. No ZIP files, no manual uploads.
|
|
171
175
|
|
|
172
176
|
```bash
|
|
173
|
-
coursecode
|
|
177
|
+
coursecode deploy
|
|
174
178
|
```
|
|
175
179
|
|
|
176
|
-
|
|
180
|
+
**Without Cloud**: Build a ZIP package and upload it to your LMS manually:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
coursecode build
|
|
184
|
+
```
|
|
177
185
|
|
|
178
|
-
**Share for review
|
|
186
|
+
**Share for review**: Export a standalone preview for stakeholders. Deploy to GitHub Pages, Netlify, or any static host:
|
|
179
187
|
|
|
180
188
|
```bash
|
|
181
189
|
coursecode preview --export
|
|
182
190
|
```
|
|
183
191
|
|
|
184
|
-
Deploy to GitHub Pages, Netlify, or any static host. Optional password protection keeps content secure.
|
|
185
|
-
|
|
186
192
|
---
|
|
187
193
|
|
|
188
194
|
## CLI Commands
|
|
@@ -194,10 +200,22 @@ Deploy to GitHub Pages, Netlify, or any static host. Optional password protectio
|
|
|
194
200
|
| `coursecode build` | Build course package (ZIP for LMS upload) |
|
|
195
201
|
| `coursecode build --format scorm1.2` | Build for specific LMS format |
|
|
196
202
|
| `coursecode mcp` | Start the MCP server for AI integration |
|
|
203
|
+
| `coursecode lint` | Validate course configuration and structure |
|
|
197
204
|
| `coursecode narration` | Generate audio narration from text |
|
|
198
205
|
| `coursecode convert` | Convert PDFs, Word, PowerPoint to markdown |
|
|
199
206
|
| `coursecode upgrade` | Upgrade to latest version |
|
|
200
207
|
|
|
208
|
+
### Cloud Commands
|
|
209
|
+
|
|
210
|
+
| Command | Description |
|
|
211
|
+
|---------|-------------|
|
|
212
|
+
| `coursecode login` | Log in to CourseCode Cloud |
|
|
213
|
+
| `coursecode logout` | Log out of CourseCode Cloud |
|
|
214
|
+
| `coursecode whoami` | Show current Cloud user and organizations |
|
|
215
|
+
| `coursecode courses` | List courses on CourseCode Cloud |
|
|
216
|
+
| `coursecode deploy` | Build and deploy to CourseCode Cloud |
|
|
217
|
+
| `coursecode status` | Show deployment status for current course |
|
|
218
|
+
|
|
201
219
|
### Output Format Options
|
|
202
220
|
|
|
203
221
|
```bash
|
|
@@ -130,18 +130,17 @@ The ZIP never includes preview/stub player assets. Preview is a separate concern
|
|
|
130
130
|
|
|
131
131
|
#### Re-Stamping for Different Formats
|
|
132
132
|
|
|
133
|
-
`lib/build-packaging.js` exports `
|
|
133
|
+
`lib/build-packaging.js` exports `stampFormat(html, format)` for re-stamping the meta tag:
|
|
134
134
|
|
|
135
135
|
```javascript
|
|
136
|
-
import {
|
|
136
|
+
import { stampFormat } from 'coursecode/build-packaging';
|
|
137
137
|
import { generateManifest } from 'coursecode/manifest';
|
|
138
138
|
|
|
139
|
-
// Re-stamp
|
|
140
|
-
|
|
139
|
+
// Re-stamp HTML string for a different format (no filesystem needed)
|
|
140
|
+
const stampedHtml = stampFormat(indexHtml, 'scorm2004');
|
|
141
141
|
|
|
142
142
|
// Generate the format-specific manifest
|
|
143
143
|
const { filename, content } = generateManifest('scorm2004', config, files, options);
|
|
144
|
-
fs.writeFileSync(`/path/to/dist/${filename}`, content);
|
|
145
144
|
```
|
|
146
145
|
|
|
147
146
|
Both are pure Node utilities
|
|
@@ -152,7 +151,7 @@ Both are pure Node utilities
|
|
|
152
151
|
|------|---------|
|
|
153
152
|
| `framework/js/state/lms-connection.js` | `getLMSFormat()` — runtime priority chain (meta → env → default) |
|
|
154
153
|
| `framework/js/drivers/driver-factory.js` | Dynamic `import()` switch — loads one driver at runtime |
|
|
155
|
-
| `lib/build-packaging.js` | `
|
|
154
|
+
| `lib/build-packaging.js` | `stampFormat()` — pure string meta tag re-stamping; `stampFormatInHtml()` — file-based wrapper |
|
|
156
155
|
| `lib/manifest/manifest-factory.js` | `generateManifest()` — generates format-specific manifests |
|
|
157
156
|
| Both `vite.config.js` files | Post-build `closeBundle` hook stamps meta tag into `dist/index.html` |
|
|
158
157
|
|
|
@@ -586,7 +585,7 @@ User: coursecode build → uploads dist/
|
|
|
586
585
|
└────────────┘
|
|
587
586
|
```
|
|
588
587
|
|
|
589
|
-
**Cloud dependencies:** The cloud app imports `
|
|
588
|
+
**Cloud dependencies:** The cloud app imports `stampFormat` and `generateManifest` directly from the `coursecode` npm package. These are pure functions — no filesystem, no Vite, no dynamic imports of user code, no `eval`. All inputs (title, version, file list) come from scanning the uploaded `dist/` or the cloud's own database.
|
|
590
589
|
|
|
591
590
|
**Security boundary:** The cloud never executes `course-config.js` or any user-authored JavaScript. The meta tag and manifest are the only format-specific artifacts, and both are generated from trusted framework source code.
|
|
592
591
|
---
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export function stampFormat(html: string, format: string): string
|
|
2
|
+
export function stampFormatInHtml(htmlPath: string, format: string): void
|
|
3
|
+
|
|
4
|
+
export function validateExternalHostingConfig(config: Record<string, unknown>): void
|
|
5
|
+
|
|
6
|
+
export function createStandardPackage(options: {
|
|
7
|
+
rootDir: string
|
|
8
|
+
distDir: string
|
|
9
|
+
config: Record<string, unknown>
|
|
10
|
+
outputDir?: string
|
|
11
|
+
}): Promise<string>
|
|
12
|
+
|
|
13
|
+
export function createProxyPackage(options: {
|
|
14
|
+
rootDir: string
|
|
15
|
+
config: Record<string, unknown>
|
|
16
|
+
clientId?: string
|
|
17
|
+
token?: string
|
|
18
|
+
outputDir?: string
|
|
19
|
+
}): Promise<string>
|
|
20
|
+
|
|
21
|
+
export function createRemotePackage(options: {
|
|
22
|
+
rootDir: string
|
|
23
|
+
config: Record<string, unknown>
|
|
24
|
+
clientId?: string
|
|
25
|
+
token?: string
|
|
26
|
+
outputDir?: string
|
|
27
|
+
}): Promise<string>
|
|
28
|
+
|
|
29
|
+
export function createExternalPackagesForClients(options: {
|
|
30
|
+
rootDir: string
|
|
31
|
+
config: Record<string, unknown>
|
|
32
|
+
outputDir?: string
|
|
33
|
+
}): Promise<void>
|
package/lib/build-packaging.js
CHANGED
|
@@ -61,24 +61,31 @@ export function validateExternalHostingConfig(config) {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
|
-
* Re-stamp the lms-format meta tag in an
|
|
65
|
-
*
|
|
66
|
-
* @param {string}
|
|
64
|
+
* Re-stamp the lms-format meta tag in an HTML string.
|
|
65
|
+
* Pure string transform — no filesystem access. Use this in cloud/serverless environments.
|
|
66
|
+
* @param {string} html - The HTML string to modify
|
|
67
67
|
* @param {string} format - The LMS format to stamp (e.g., 'scorm2004', 'cmi5')
|
|
68
|
+
* @returns {string} The modified HTML string
|
|
68
69
|
*/
|
|
69
|
-
export function
|
|
70
|
-
let html = fs.readFileSync(htmlPath, 'utf-8');
|
|
71
|
-
// Replace existing meta tag or insert after charset
|
|
70
|
+
export function stampFormat(html, format) {
|
|
72
71
|
const existingMeta = /<meta\s+name="lms-format"\s+content="[^"]*"\s*\/?>/;
|
|
73
72
|
if (existingMeta.test(html)) {
|
|
74
|
-
|
|
75
|
-
} else {
|
|
76
|
-
html = html.replace(
|
|
77
|
-
'<meta charset="UTF-8" />',
|
|
78
|
-
`<meta charset="UTF-8" />\n <meta name="lms-format" content="${format}" />`
|
|
79
|
-
);
|
|
73
|
+
return html.replace(existingMeta, `<meta name="lms-format" content="${format}" />`);
|
|
80
74
|
}
|
|
81
|
-
|
|
75
|
+
return html.replace(
|
|
76
|
+
'<meta charset="UTF-8" />',
|
|
77
|
+
`<meta charset="UTF-8" />\n <meta name="lms-format" content="${format}" />`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Re-stamp the lms-format meta tag in an index.html file on disk.
|
|
83
|
+
* @param {string} htmlPath - Absolute path to the index.html to modify
|
|
84
|
+
* @param {string} format - The LMS format to stamp (e.g., 'scorm2004', 'cmi5')
|
|
85
|
+
*/
|
|
86
|
+
export function stampFormatInHtml(htmlPath, format) {
|
|
87
|
+
const html = fs.readFileSync(htmlPath, 'utf-8');
|
|
88
|
+
fs.writeFileSync(htmlPath, stampFormat(html, format), 'utf-8');
|
|
82
89
|
}
|
|
83
90
|
|
|
84
91
|
export async function createStandardPackage({ rootDir, distDir, config, outputDir }) {
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Stub Player
|
|
2
|
+
export { generateStubPlayer } from './stub-player.js'
|
|
3
|
+
export type { StubPlayerConfig } from './stub-player.js'
|
|
4
|
+
|
|
5
|
+
// Manifest Generation
|
|
6
|
+
export function generateManifest(
|
|
7
|
+
format: string,
|
|
8
|
+
config: Record<string, unknown>,
|
|
9
|
+
files: string[],
|
|
10
|
+
options?: Record<string, unknown>
|
|
11
|
+
): { filename: string; content: string }
|
|
12
|
+
|
|
13
|
+
export function getSchemaFiles(format: string): string[]
|
|
14
|
+
|
|
15
|
+
// Content Parsing
|
|
16
|
+
export function parseCourse(coursePath: string): Promise<Record<string, unknown>>
|
|
17
|
+
export function parseSlideSource(source: string, slideId: string): Record<string, unknown>
|
|
18
|
+
export function extractAssessment(source: string, slideId: string): Record<string, unknown> | null
|
|
19
|
+
export function extractNarration(source: string): Record<string, unknown> | null
|
|
20
|
+
export function extractInteractions(content: string, slideId: string): Record<string, unknown>[]
|
|
21
|
+
export function parseElements(html: string): Record<string, unknown>[]
|
|
22
|
+
export function resolveElementByPath(elements: Record<string, unknown>[], targetPath: string): Record<string, unknown> | null
|
|
23
|
+
|
|
24
|
+
// Build
|
|
25
|
+
export function build(options?: Record<string, unknown>): Promise<void>
|
|
26
|
+
|
|
27
|
+
// Build Packaging
|
|
28
|
+
export function stampFormat(html: string, format: string): string
|
|
29
|
+
export function stampFormatInHtml(htmlPath: string, format: string): void
|
|
30
|
+
export function validateExternalHostingConfig(config: Record<string, unknown>): void
|
|
31
|
+
export function createStandardPackage(options: Record<string, unknown>): Promise<string>
|
|
32
|
+
export function createProxyPackage(options: Record<string, unknown>): Promise<string>
|
|
33
|
+
export function createRemotePackage(options: Record<string, unknown>): Promise<string>
|
|
34
|
+
export function createExternalPackagesForClients(options: Record<string, unknown>): Promise<void>
|
|
35
|
+
|
|
36
|
+
// Build Linter
|
|
37
|
+
export function lintCourse(courseConfig: Record<string, unknown>, coursePath: string): { errors: string[]; warnings: string[] }
|
|
38
|
+
export function lint(options?: Record<string, unknown>): Promise<void>
|
|
39
|
+
|
|
40
|
+
// Validation Rules
|
|
41
|
+
export function flattenStructure(structure: unknown[]): unknown[]
|
|
42
|
+
export function validateAssessmentConfig(...args: unknown[]): void
|
|
43
|
+
export function validateQuestionConfig(...args: unknown[]): void
|
|
44
|
+
export function validateEngagement(...args: unknown[]): void
|
|
45
|
+
export function validateRequirementConfig(...args: unknown[]): void
|
|
46
|
+
export function validateGlobalConfig(...args: unknown[]): { warnings: string[]; objectiveIds: Set<string> }
|
|
47
|
+
export function formatLintResults(results: { errors: string[]; warnings: string[] }): string
|
|
48
|
+
|
|
49
|
+
// Path utilities
|
|
50
|
+
export function getTemplatePath(): string
|
|
51
|
+
export function getFrameworkPath(): string
|
|
52
|
+
export function getSchemasPath(): string
|
package/lib/index.js
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function generateManifest(
|
|
2
|
+
format: 'scorm2004' | 'scorm1.2' | 'cmi5' | 'scorm1.2-proxy' | 'scorm2004-proxy' | 'cmi5-remote' | 'lti',
|
|
3
|
+
config: Record<string, unknown>,
|
|
4
|
+
files: string[],
|
|
5
|
+
options?: { externalUrl?: string }
|
|
6
|
+
): { filename: string; content: string }
|
|
7
|
+
|
|
8
|
+
export function getSchemaFiles(
|
|
9
|
+
format: 'scorm2004' | 'scorm1.2' | 'cmi5' | 'lti'
|
|
10
|
+
): string[]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface StubPlayerConfig {
|
|
2
|
+
title: string
|
|
3
|
+
launchUrl: string
|
|
4
|
+
storageKey: string
|
|
5
|
+
passwordHash?: string
|
|
6
|
+
isLive?: boolean
|
|
7
|
+
liveReload?: boolean
|
|
8
|
+
courseContent?: string
|
|
9
|
+
startSlide?: string | number
|
|
10
|
+
isDesktop?: boolean
|
|
11
|
+
moduleBasePath?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function generateStubPlayer(config: StubPlayerConfig): string
|
|
15
|
+
export function escapeHtml(str: string): string
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coursecode",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Multi-format course authoring framework with CLI tools (SCORM 2004, SCORM 1.2, cmi5, LTI 1.3)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -20,12 +20,22 @@
|
|
|
20
20
|
"THIRD_PARTY_NOTICES.md"
|
|
21
21
|
],
|
|
22
22
|
"exports": {
|
|
23
|
-
".":
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"./
|
|
28
|
-
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./lib/index.d.ts",
|
|
25
|
+
"default": "./lib/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./manifest": {
|
|
28
|
+
"types": "./lib/manifest/manifest-factory.d.ts",
|
|
29
|
+
"default": "./lib/manifest/manifest-factory.js"
|
|
30
|
+
},
|
|
31
|
+
"./build-packaging": {
|
|
32
|
+
"types": "./lib/build-packaging.d.ts",
|
|
33
|
+
"default": "./lib/build-packaging.js"
|
|
34
|
+
},
|
|
35
|
+
"./stub-player": {
|
|
36
|
+
"types": "./lib/stub-player.d.ts",
|
|
37
|
+
"default": "./lib/stub-player.js"
|
|
38
|
+
}
|
|
29
39
|
},
|
|
30
40
|
"scripts": {
|
|
31
41
|
"dev": "VITE_COURSECODE_LOCAL=true npx vite build --config vite.framework-dev.config.js --mode development --watch",
|