@plasius/learning 0.3.0 → 0.5.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 (49) hide show
  1. package/README.md +32 -0
  2. package/dist/chunk-2UIOBMJZ.js +44 -0
  3. package/dist/chunk-2UIOBMJZ.js.map +1 -0
  4. package/dist/chunk-OXWMIHYI.js +6076 -0
  5. package/dist/chunk-OXWMIHYI.js.map +1 -0
  6. package/dist/course-authoring-DImvrK5r.d.cts +514 -0
  7. package/dist/course-authoring-DImvrK5r.d.ts +514 -0
  8. package/dist/courses/meteor-shield.cjs +369 -0
  9. package/dist/courses/meteor-shield.cjs.map +1 -0
  10. package/dist/courses/meteor-shield.d.cts +6 -0
  11. package/dist/courses/meteor-shield.d.ts +6 -0
  12. package/dist/courses/meteor-shield.js +175 -0
  13. package/dist/courses/meteor-shield.js.map +1 -0
  14. package/dist/courses/pixel-trail-challenge.cjs +366 -0
  15. package/dist/courses/pixel-trail-challenge.cjs.map +1 -0
  16. package/dist/courses/pixel-trail-challenge.d.cts +6 -0
  17. package/dist/courses/pixel-trail-challenge.d.ts +6 -0
  18. package/dist/courses/pixel-trail-challenge.js +172 -0
  19. package/dist/courses/pixel-trail-challenge.js.map +1 -0
  20. package/dist/courses/rescue-crew-commander.cjs +369 -0
  21. package/dist/courses/rescue-crew-commander.cjs.map +1 -0
  22. package/dist/courses/rescue-crew-commander.d.cts +6 -0
  23. package/dist/courses/rescue-crew-commander.d.ts +6 -0
  24. package/dist/courses/rescue-crew-commander.js +175 -0
  25. package/dist/courses/rescue-crew-commander.js.map +1 -0
  26. package/dist/courses/robot-maze-dash.cjs +355 -0
  27. package/dist/courses/robot-maze-dash.cjs.map +1 -0
  28. package/dist/courses/robot-maze-dash.d.cts +6 -0
  29. package/dist/courses/robot-maze-dash.d.ts +6 -0
  30. package/dist/courses/robot-maze-dash.js +161 -0
  31. package/dist/courses/robot-maze-dash.js.map +1 -0
  32. package/dist/courses/skywing-sprint.cjs +367 -0
  33. package/dist/courses/skywing-sprint.cjs.map +1 -0
  34. package/dist/courses/skywing-sprint.d.cts +6 -0
  35. package/dist/courses/skywing-sprint.d.ts +6 -0
  36. package/dist/courses/skywing-sprint.js +173 -0
  37. package/dist/courses/skywing-sprint.js.map +1 -0
  38. package/dist/courses/star-defender-squadron.cjs +369 -0
  39. package/dist/courses/star-defender-squadron.cjs.map +1 -0
  40. package/dist/courses/star-defender-squadron.d.cts +6 -0
  41. package/dist/courses/star-defender-squadron.d.ts +6 -0
  42. package/dist/courses/star-defender-squadron.js +175 -0
  43. package/dist/courses/star-defender-squadron.js.map +1 -0
  44. package/dist/index.cjs.map +1 -1
  45. package/dist/index.d.cts +3 -504
  46. package/dist/index.d.ts +3 -504
  47. package/dist/index.js +44 -6048
  48. package/dist/index.js.map +1 -1
  49. package/package.json +31 -1
package/README.md CHANGED
@@ -44,6 +44,38 @@ export remain available unchanged.
44
44
 
45
45
  ## Complete course and account-save contracts
46
46
 
47
+ Complete learner curricula are separate lazy entry points. Import
48
+ `{ course, practice }` from `@plasius/learning/courses/robot-maze-dash` for the
49
+ Robot Maze `2.0.0` course: six distinct missions, 54 guided activities, a bounded
50
+ visual starter project, function references, formative concept checks, debugging
51
+ guidance and extensions. Formative answers are learner-safe teaching material;
52
+ they are not protected runtime assessments or completion authority. Hosts verify
53
+ responses, run protected checks and persist evidence independently.
54
+ The root exports `CoursePracticeQuestion` as a type without importing lesson data.
55
+
56
+ The same lazy course boundary also provides `courses/skywing-sprint`,
57
+ `courses/meteor-shield` and `courses/pixel-trail-challenge`. Each has six authored
58
+ missions and 54 activities, 18 formative questions, a real editable `game.js`
59
+ starter and explicit state/input references. Their respective sequences teach
60
+ flight and input timing; vector defence, timed shields and resource accounting;
61
+ and ordered grid movement, bounded placement and moving-tail collisions. Hosts
62
+ must implement and verify each documented game contract before exposing its
63
+ course; lesson publication alone is not evidence of a working playable module.
64
+
65
+ `courses/rescue-crew-commander` adds shared-job ownership, bounded breadth-first
66
+ routes, deterministic dispatch, round-trip energy, delivery conservation and
67
+ recoverable route changes. `courses/star-defender-squadron` adds input/formation
68
+ control, single-hit projectiles, damage grace periods, timed shields and complete
69
+ wave outcomes. Both follow the same six-mission/54-activity contract with authored
70
+ questions, starter projects and references, and require their own host validation.
71
+
72
+ The runtime is supplied separately by `@plasius/learning-runtime`; this package
73
+ does not execute the project or declare host readiness. The seventeen-course
74
+ programme remains in development. This additive content does not alter immutable
75
+ catalogue/pricing records or enable a public host rollout. New hosts compose
76
+ their existing access controls with an independently disabled complete-course
77
+ flag and must validate the full learner journey before enabling it.
78
+
47
79
  `LearningCourseV1` defines six missions with nine activities each, editable project
48
80
  files, learner guidance and a capstone assessment identifier. Use
49
81
  `validateLearningCourse` or `parseLearningCourse` for publication and loading.
@@ -0,0 +1,44 @@
1
+ import {
2
+ LEARNING_COURSE_STAGE_ORDER,
3
+ parseLearningCourse
4
+ } from "./chunk-OXWMIHYI.js";
5
+
6
+ // src/courses/course-authoring.ts
7
+ function authorCourse(header, missions) {
8
+ const course = parseLearningCourse({
9
+ ...header,
10
+ schemaVersion: "1",
11
+ moduleVersion: "2.0.0",
12
+ moduleId: `junior-coder.${header.slug}`,
13
+ runtimeId: `${header.slug}.v2`,
14
+ estimatedMinutes: missions.length * 60,
15
+ completionAssessmentId: `${header.slug}.final`,
16
+ completionBadge: { id: `${header.slug}.completed`, title: `${header.title} creator` },
17
+ missions: missions.map((mission, index) => ({
18
+ id: `${header.slug}.m${index + 1}`,
19
+ title: mission.title,
20
+ concepts: mission.concepts,
21
+ goals: mission.goals,
22
+ estimatedMinutes: 60,
23
+ assessmentId: `${header.slug}.m${index + 1}.assessment`,
24
+ extension: mission.extension,
25
+ stages: LEARNING_COURSE_STAGE_ORDER.map((kind) => ({
26
+ id: `${header.slug}.m${index + 1}.${kind}`,
27
+ kind,
28
+ title: `${kind.charAt(0).toUpperCase()}${kind.slice(1)}: ${mission.title}`,
29
+ instruction: mission.activities[kind][0],
30
+ help: mission.activities[kind][1]
31
+ }))
32
+ }))
33
+ });
34
+ const practice = structuredClone(missions.flatMap((mission, index) => ["learn", "predict", "explain"].map((kind) => ({ ...mission.questions[kind], stageId: `${header.slug}.m${index + 1}.${kind}` }))));
35
+ for (const question of practice) {
36
+ if (question.question.trim().length < 20 || question.feedback.trim().length < 40 || question.choices.length !== 3 || question.choices.some((choice) => choice.trim().length < 2) || new Set(question.choices).size !== 3 || !Number.isInteger(question.correctChoice) || question.correctChoice < 0 || question.correctChoice > 2) throw new Error("Invalid course practice question.");
37
+ }
38
+ return { course, practice };
39
+ }
40
+
41
+ export {
42
+ authorCourse
43
+ };
44
+ //# sourceMappingURL=chunk-2UIOBMJZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/courses/course-authoring.ts"],"sourcesContent":["import { LEARNING_COURSE_STAGE_ORDER, parseLearningCourse, type LearningCourseV1 } from \"../course-contracts.js\";\nimport type { MissionStageKindV1 } from \"../contracts.js\";\n\n/** Formative checks are learner-visible teaching material, not protected assessments. */\nexport interface CoursePracticeQuestion {\n stageId: string;\n question: string;\n choices: [string, string, string];\n correctChoice: 0 | 1 | 2;\n feedback: string;\n}\nexport type PracticeDraft = Omit<CoursePracticeQuestion, \"stageId\">;\nexport interface CourseMissionDraft {\n title: string;\n concepts: string[];\n goals: string[];\n extension: string;\n activities: Record<MissionStageKindV1, [instruction: string, help: string]>;\n questions: Record<\"learn\" | \"predict\" | \"explain\", PracticeDraft>;\n}\ntype CourseHeader = Omit<LearningCourseV1, \"schemaVersion\" | \"moduleVersion\" | \"moduleId\" | \"runtimeId\" | \"estimatedMinutes\" | \"completionAssessmentId\" | \"completionBadge\" | \"missions\">;\n\n/** Only identifiers and activity framing are shared; each lesson is independently authored. */\nexport function authorCourse(header: CourseHeader, missions: CourseMissionDraft[]): { course: LearningCourseV1; practice: CoursePracticeQuestion[] } {\n const course = parseLearningCourse({ ...header, schemaVersion: \"1\", moduleVersion: \"2.0.0\", moduleId: `junior-coder.${header.slug}`,\n runtimeId: `${header.slug}.v2`, estimatedMinutes: missions.length * 60,\n completionAssessmentId: `${header.slug}.final`, completionBadge: { id: `${header.slug}.completed`, title: `${header.title} creator` },\n missions: missions.map((mission, index) => ({\n id: `${header.slug}.m${index + 1}`, title: mission.title, concepts: mission.concepts, goals: mission.goals,\n estimatedMinutes: 60, assessmentId: `${header.slug}.m${index + 1}.assessment`, extension: mission.extension,\n stages: LEARNING_COURSE_STAGE_ORDER.map(kind => ({ id: `${header.slug}.m${index + 1}.${kind}`, kind,\n title: `${kind.charAt(0).toUpperCase()}${kind.slice(1)}: ${mission.title}`,\n instruction: mission.activities[kind][0], help: mission.activities[kind][1] })),\n })),\n });\n const practice = structuredClone(missions.flatMap((mission, index) => ([\"learn\", \"predict\", \"explain\"] as const)\n .map(kind => ({ ...mission.questions[kind], stageId: `${header.slug}.m${index + 1}.${kind}` }))));\n for (const question of practice) {\n if (question.question.trim().length < 20 || question.feedback.trim().length < 40\n || question.choices.length !== 3 || question.choices.some(choice => choice.trim().length < 2) || new Set(question.choices).size !== 3\n || !Number.isInteger(question.correctChoice) || question.correctChoice < 0 || question.correctChoice > 2) throw new Error(\"Invalid course practice question.\");\n }\n return { course, practice };\n}\n"],"mappings":";;;;;;AAuBO,SAAS,aAAa,QAAsB,UAAkG;AACnJ,QAAM,SAAS,oBAAoB;AAAA,IAAE,GAAG;AAAA,IAAQ,eAAe;AAAA,IAAK,eAAe;AAAA,IAAS,UAAU,gBAAgB,OAAO,IAAI;AAAA,IAC/H,WAAW,GAAG,OAAO,IAAI;AAAA,IAAO,kBAAkB,SAAS,SAAS;AAAA,IACpE,wBAAwB,GAAG,OAAO,IAAI;AAAA,IAAU,iBAAiB,EAAE,IAAI,GAAG,OAAO,IAAI,cAAc,OAAO,GAAG,OAAO,KAAK,WAAW;AAAA,IACpI,UAAU,SAAS,IAAI,CAAC,SAAS,WAAW;AAAA,MAC1C,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC;AAAA,MAAI,OAAO,QAAQ;AAAA,MAAO,UAAU,QAAQ;AAAA,MAAU,OAAO,QAAQ;AAAA,MACrG,kBAAkB;AAAA,MAAI,cAAc,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC;AAAA,MAAe,WAAW,QAAQ;AAAA,MAClG,QAAQ,4BAA4B,IAAI,WAAS;AAAA,QAAE,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,IAAI,IAAI;AAAA,QAAI;AAAA,QAC7F,OAAO,GAAG,KAAK,OAAO,CAAC,EAAE,YAAY,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC,KAAK,QAAQ,KAAK;AAAA,QACxE,aAAa,QAAQ,WAAW,IAAI,EAAE,CAAC;AAAA,QAAG,MAAM,QAAQ,WAAW,IAAI,EAAE,CAAC;AAAA,MAAE,EAAE;AAAA,IAClF,EAAE;AAAA,EACJ,CAAC;AACD,QAAM,WAAW,gBAAgB,SAAS,QAAQ,CAAC,SAAS,UAAW,CAAC,SAAS,WAAW,SAAS,EAClG,IAAI,WAAS,EAAE,GAAG,QAAQ,UAAU,IAAI,GAAG,SAAS,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC;AAClG,aAAW,YAAY,UAAU;AAC/B,QAAI,SAAS,SAAS,KAAK,EAAE,SAAS,MAAM,SAAS,SAAS,KAAK,EAAE,SAAS,MACzE,SAAS,QAAQ,WAAW,KAAK,SAAS,QAAQ,KAAK,YAAU,OAAO,KAAK,EAAE,SAAS,CAAC,KAAK,IAAI,IAAI,SAAS,OAAO,EAAE,SAAS,KACjI,CAAC,OAAO,UAAU,SAAS,aAAa,KAAK,SAAS,gBAAgB,KAAK,SAAS,gBAAgB,EAAG,OAAM,IAAI,MAAM,mCAAmC;AAAA,EACjK;AACA,SAAO,EAAE,QAAQ,SAAS;AAC5B;","names":[]}