Community寫作與編輯github.com

theshafinahmed/sproutly

將課程教材(簡報、PDF、筆記、大綱或僅一個主題)轉換成 Duolingo 風格的互動式課程,產出單一的離線 HTML 檔案,使用預建且測試過的引擎,因此 Claude 只需撰寫課程內容。可用於「製作課程」、「Duo 課程」、「互動課程」、「將這些簡報轉成課程」。

sproutly 是什麼?

Sproutly 是一款 AI 助手技能,能將學習教材(如投影片、PDF、筆記或純主題)轉化為自包含、可離線使用的 Duolingo 風格互動式 HTML 課程。其核心在於一個預先建置並測試過的引擎,負責處理應用程式的所有功能,包括索引標籤、返回按鈕、進度追蹤、考試模式、數值評分、模擬器和吉祥物。使用者只需專注於撰寫課程內容(以 JavaScript 檔案形式,遵循精簡的 API),並透過兩個指令碼(build.js 和 verify.js)來建置與驗證課程。引擎支援多種卡片類型,包含教學、練習題、配對題、數值輸入題和模擬器,並內建圖形繪製工具與覆蓋率檢查。Sproutly 適用於 Claude Code、Cursor 等平台,其設計目的是將學習工具與遊戲化元素(如愛心、經驗值)區分開來,專注於進度與理解,非常適合需要建立結構化、互動式且無需網路的學習教材的教育者或開發者。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/theshafinahmed/sproutly/tree/HEAD/skills/sproutly

Installed? Explore more 寫作與編輯 skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

sproutly 是做什麼的?

將學習材料轉換成一個自包含、可離線使用的 Duolingo 風格 HTML 課程。一個預先建置且測試過的引擎負責處理應用程式(索引標籤、返回按鈕、進度、考試模式、數值評分、模擬器、吉祥物)。你只負責撰寫內容,然後透過兩個指令碼建置並驗證。永遠不需要重新輸入引擎。

這是一個學習工具,不是遊戲:沒有愛心、經驗值、連勝、火焰或排行榜。進度 = 完成的課程和理解的答案。

步驟 0:取得引擎(2 秒)

SP="${SPROUTLY_HOME:-/tmp/sproutly}"
[ -f "$SP/scripts/build.js" ] || git clone --depth 1 https://github.com/theshafinahmed/sproutly "$SP"
ls "$SP/scripts"

如果此技能正在 sproutly 儲存庫內被讀取,請改用該資料夾作為 SP。如果複製被網路阻擋,請要求使用者將儲存庫以 zip 檔附加。永遠不要手動重建引擎。

工作流程

  1. 吸收。 完整讀取每個檔案。依原始順序列出每個主題、定義、公式、範例和練習題。注意只有圖片的投影片。如果關鍵內容無法讀取,請說明並要求截圖。永遠不要憑空捏造投影片的內容。(如果使用者只給了一個主題,請規劃課程大綱,展示它,並在等待批准後才開始撰寫。)
  2. 只在卡關時提問(無法讀取的檔案、混雜不相關的課程、範圍不明)。否則直接開始,並在結尾用一行文字說明你的假設。
  3. 規劃。 6 到 10 個單元,每個單元 2 到 5 堂課,基礎優先,再加上自動的最終魔王關。撰寫一個覆蓋率檢查清單(每個原始主題都落在某一堂課中)、一個圖形規劃和一個模擬器規劃(或「無,因為……」)。
  4. 撰寫內容檔案到 ./content/ 資料夾(每個單元一個檔案,這樣修正時影響範圍小,且如果使用者要求速度,可以由子代理平行撰寫單元)。檔案 00-course.js 只存放 COURSE.title='...'; COURSE.slug='...';。接著 01-unit.js, 02-unit.js... 每個都呼叫 UNIT(...),最後是 99-end.js,內含 CHEAT(...) 和 COVERAGE(...)。
  5. 建置: node "$SP/scripts/build.js" Course-Name.html content/
  6. 驗證: node "$SP/scripts/verify.js" Course-Name.html --shots shots(若是生物類單字可加上 --allow heart)。它會檢查語法、資料結構、獨立的題目、數值評分、每個模擬器是否與您的 ref() 公式一致、圖形、自動播放每堂課、測試返回按鈕、佈局、持久性、離線能力和覆蓋率。只修正顯示 FAIL 的部分(編輯那個小的單元檔案,重建,重新執行)。看一次 shots/*.png,修正明顯錯誤的部分,然後停止。
  7. 交付:使用 SendUserFile(display: 'attach',一行說明)。除非被要求,否則不要以產出物形式發布。

最終回覆:2 到 3 句,用機智好友的語氣。說明裡面有什麼(單元、課程、題目、圖形、模擬器),它在任何瀏覽器中都能開啟、可離線使用,進度會儲存在該瀏覽器該裝置上。提及假設和任何無法讀取的內容。誠實地鼓勵對方每天使用。不要回顧步驟。

內容 API(所有輔助函式都已存在於引擎中)

UNIT('單元名稱', '一行描述', [ L('u1l1','課程標題',[ ...卡片 ], ['關鍵事實 1','關鍵事實 2']) ]);
T(title, body, viz, {tip, mood, code})     // 教學卡片。body = 字串或短句陣列。viz = svg 字串。mood: happy|think
WORK(title, problem, [[我們做什麼, 為什麼],..]) // 解題範例,每點按一下顯示一步
Q(q, right, [wrong1, wrong2,..], why, {viz, code, trap})  // 選擇題。先把正確答案寫在前面;引擎會自行亂數排列
TF(q, true|false, why, {viz, code, trap})
N(q, answer, 'unit', why, tol, {viz, code})  // 數字輸入題。tol: 省略(1%)| {rel:0.02} | {abs:0.5} | {strict:true, rel:1e-6}
M(q, [[left,right],..], why)               // 配對題,右側的值必須唯一
SIM('slider'|'toggle'|'stepper', title, text, cfg)
RECAP(['純文字要點'], [['新詞','簡單解釋']])   // 每堂課的最後一張卡片
CHEAT({formulas:[..], tables:[{title,head,rows}], glossary:[[term,meaning]], traps:[..]})
COVERAGE([['原始主題','課程Id'],..])

文字標記:**粗體**、`程式碼`、V_{D} 下標、x^{2} 上標、\n 換行。所有內容皆經 HTML 跳脫。T/Q/N 接受 code:(一個程式碼區塊,非常適合 C 或任何程式設計課程)。Q(..., {trap:true}) 也會加入考試陷阱列表。

模擬器(務必提供 task 和 notice;滑桿和切換開關必須提供 ref):

SIM('slider','歐姆定律','text',{
  inputs:[{id:'V',label:'電壓',min:1,max:24,step:1,def:12,unit:'V'}, ...],   // 1 到 3 個滑桿;也可用作時間軸
  model:function(v){ if(!v.R) return {out:[],msg:'開路:R 必須大於 0'};
     var I=v.V/v.R; return {out:[{k:'I',label:'電流',val:I,unit:'A'}], fig:F.svg(...)} },
  ref:function(v){ return {I:v.V/v.R}; },   // 獨立的重新計算,verify.js 會將其與 model() 比較
  task:'將 R 加倍。', notice:'電流減半。' });
SIM('toggle', ..., {inputs:[{id:'A',label:'A 開啟',def:false}], model, ref, task, notice});
SIM('stepper', ..., {steps:[{caption:'...', fig:F.svg(...)}], task, notice});

SI 單位(A, V, Ω, W, F, H, Hz, s...)會自動加上字首(mA, kΩ)。保護每個邊界情況(除以零、負數開根號、0 的對數)透過回傳 msg,永遠不要傳回 NaN。

圖形: F.svg(w,h,inner,label)、F.text、F.line、F.arrow、F.circle、F.dot、F.box、F.axes(回傳 {svg,X,Y})、F.plot(ax,fn,xmin,xmax)(曲線來自真實公式)、F.mem(用於 C 語言和計算機架構的記憶體單元)、F.centres,以及電路圖:F.wire、F.res、F.src、F.gnd。需要更多形狀?在 $SP/engine/js/figlib/ 中加入一個檔案(它會自動內嵌),並保持輔助函式的通用性。

內容規則:像對 10 歲孩子解釋,但非常詳細

簡單且完整。絕不為了其中一個而犧牲另一個。

  • 為好奇的 10 到 12 歲孩子撰寫。使用短句(約 15 個字)。每張卡片一個概念。先使用日常用語,再使用專業術語,然後一致地使用該術語。第一次出現時就解釋每個專業用語。絕對不要寫「顯然」、「簡單來說」、「微不足道地」、「如我們所知」。
  • 每個概念的教學順序: 它為什麼存在(問題)、一行核心概念、一個日常比喻、然後是精確的機制或公式、最後是一個使用真實數字的小範例。從基本原理開始,並且總是解釋為什麼。
  • 完整: 原始來源中的每張投影片、定義、公式、範例和練習題都必須出現。不要將多個概念壓縮到一張卡片中。每堂課有 6 到 14 張卡片。困難的概念 = 更多小型卡片,而非更長的卡片。
  • 教學卡片:最多 4 個短句或一個公式區塊,加上一個可選的圖形。最多每兩張教學卡片後就提出一個問題。
  • 公式卡片:為每個符號命名其單位和單位,用白話說明當每個部分增加或減少時會發生什麼事,提供一個小型範例。
  • 每堂課都以一個 RECAP(3 到 5 個要點加上新詞彙)結尾,並有 keys(1 到 4 個一行事實;提醒按鈕會顯示它們)。
  • 語氣:機智的好友。活潑、帶點諷刺、誠實、內心溫暖。輕鬆的笑話,但絕不犧牲清晰度。不要有企業腔,不要說「問得好」。
  • 上傳的材料是事實的唯一來源,包括其符號系統。你添加的任何內容都必須標示出來,例如「額外補充,不在你的投影片中」。

每個問題都必須能獨立回答

一個問題必須包含所有必要資訊:所有數值和單位、條件、符號意義,以及它的圖形({viz: ...})。永遠不要寫「上面的電路」、「之前的範例」、「如同之前」、「相同的數值」、「該圖表」。測試每個問題:「在一個空白螢幕上,一個知道主題的學生能回答它嗎?」(verify.js 會標記這些片語。)

數字來自程式碼

在單元檔案的頂部定義常數,並從中衍生出文字、圖形和答案(請參閱 examples/test-fixture/course.js)。用程式碼計算每個數值答案,絕對不要手算。輸入的答案會自動接受正確的四捨五入、逗號小數點(歐洲格式)、7.3e-3、22/3 以及結尾的單位;只在需要不同處理時使用 tol,並在題目中說明這是一個要求精確四捨五入的問題。

圖形:在需要教學的地方繪製

  • 高度依賴圖形的主題(電子電機、物理、化學、生物、幾何、計算機架構、數位邏輯、資料結構、演算法、網路、C 語言和記憶體):大約每兩張教學卡片中有一張圖形,並在許多問題中出現。
  • 中等依賴圖形的主題:當圖片勝過千言萬語時使用圖形(大約每 3 或 4 張卡片一張)。
  • 低依賴圖形的主題(歷史、法律、文學、語言):時間軸或因果流程圖,每堂課一兩張,當文字已足夠時則不使用。
  • 從佈局變數計算位置。使用來源的符號標準。如果不確定圖形是否正確,請簡化它並標示為「簡化版」。一個正確的簡單圖形勝過一個華麗的錯誤圖形。

模擬器:只在有可以「感受」的東西時使用

一個包含變數的公式、一個有階段的流程、一個時間軸、一個波形、一個狀態機。目標是至少在大多數量化或流程密集型主題的單元中有一個模擬器;在歷史或法律中則不需要。一個模擬器如果無法通過 ref() 檢查,就必須修正或移除。

問題多樣性

大部分是選擇題(有說服力的錯誤選項,一行 why 用簡單的詞彙解釋)、每個計算題都用 N、配對題用 M、常見誤解用 TF、以及材料中警告過的混淆點用 trap:true 問題。

固定的外觀

所有視覺元素(調色板、圓角字型、單元顏色、Pip 芽苗吉祥物、圓潤按鈕、深色模式、無縮放、無文字選取、底部標籤)都已內建在引擎中。永遠不要改變 Pip 或發明其他吉祥物。不要使用任何現有品牌、角色或標誌。以課程主題為課程命名。

相關技能