MCPInstall

static-spa-conversion

Use this skill when you have structured course content (or any chapter-based dataset) in markdown form and need to turn it into a working interactive website — without picking a framework, without a build step. Triggers on phrases like "做成網頁", "轉成 SPA", "course-data.js", "render 函式", "把講義變網頁", "static site from markdown", "vanilla JS site", "no-framework site", "single-page app from markdown". The output is a vanilla HTML + JS single-page app that opens with npx serve and persists state in localStorage. Always invoke AFTER course-content-authoring (content stable), BEFORE static-spa-interactions (this skill produces the scaffold; interactions adorn it).

Installs
65
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/kevintsai1202/teaching-site-skills --skill static-spa-conversion
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads static-spa-conversion automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

Static SPA Conversion

Schema authority: all window.COURSE field names come from _shared/domain-primitives.md. When the schema example below diverges from that file, that file wins.

Starter templates (copy these, don't re-derive):

  • templates/index.html — scaffold shell with render pipeline skeleton
  • templates/course-data.template.js — empty schema example with TODO markers for every primitive
  • ../teaching-site-design-system/templates/tokens.css — paste into <style> block, or copy as style.css next to index.html

Reference implementation: d:/GitHub/ai-workshop/index.html (4125 lines, fully populated). Use as visual + render-pattern reference; do not copy course-specific content from it.

Filename convention (English-first): course-package/, day{n}/outline.md, day{n}/content.md, materials/, overview.md. Legacy Chinese names (完整課程包/, 課程大綱.md, 教學素材/, etc.) are deprecated — see _shared/domain-primitives.md §0 for full mapping.

This skill turns chapter-based markdown content into a working single-page app. The architectural commitments are deliberate and worth understanding before you start.

The Three Architectural Commitments

  1. Vanilla HTML + JS, no framework, no bundler. No React, no Vite, no TypeScript build. Why: course websites have multi-year lifespans and are often handed to non-developer instructors. A .html you can open and edit beats a node_modules graveyard every time. Also: the content is the value, not the tech.

  2. Data and rendering live in different files. A course-data.js holds everything the course is as a single JS object (window.COURSE). An index.html holds how the course is shown. Instructors editing tomorrow's lesson never need to touch HTML.

  3. localStorage for persistence, no backend. Progress, theme, zoom — all client-side. Easier hosting, no privacy headaches. The cost: state is per-browser. Accept it.

Standard File Layout

project-root/
├── index.html              ← the single SPA (CSS + JS inline; ~3000 lines is normal)
├── course-data.js          ← window.COURSE = { ... }
├── instructor-data.js      ← optional: window.INSTRUCTOR (if scraped/external)
├── tools-data.js           ← optional: window.TOOLS (if showcasing tools)
├── package.json            ← just `{"scripts": {"serve": "npx serve ."}}` and scraping tooling
├── assets/                 ← images, illustrations
└── course-package/             ← markdown source (read-only from SPA's perspective)
    └── materials/           ← files linked from the SPA via getMaterialUrl()

index.html includes data files via plain <script src="course-data.js"></script> — no module imports, no fetch. The browser loads them in order, populating window.COURSE before init() runs.

The window.COURSE Schema

The single most important artifact. Design it carefully — every render function depends on it. Standard shape:

window.COURSE = {
  meta: {                              // top-level course metadata
    title: '...',
    audience: '...',
    hoursTotal: 24,
    days: [                            // index drives sidebar chapter list
      { id: 'day1', title: 'Day 1: ...', hours: 6, schedule: '...' },
      ...
    ],
    classroom: { name: '...', mapUrl: '...' }
  },
  sharedCase: { /* persistent fictional scenario */ },
  day1: {
    hero: { title, lead, illustration },
    units: [
      {
        id: 'u-1',                     // stable, never renamed
        title: '...',
        timeRange: '14:00–14:50',
        goals: [...],                  // learning outcomes
        tasks: [                       // ← these IDs are localStorage keys
          { id: 'd1-u1-t1', text: '...', done: false }
        ],
        prompts: [                     // optional: copyable templates
          { id: '...', title: '...', body: '...' }
        ],
        materials: [                   // optional: per-unit material refs
          { id: '...', name: '...', type: 'PDF 文件' }
        ],
        illustrations: [               // 1–3 entries, see Stage 5 Coverage Floor
          { name: 'day1-u1-hero.png',  kind: 'hero',    alt: '...', spec: '...' },
          { name: 'day1-u1-flow.svg',  kind: 'diagram', alt: '...', spec: '...' }
        ]
        // legacy single `illustration: 'day1-u1.png'` still accepted; treat as
        // illustrations: [{ name, kind: 'hero' }] and migrate when convenient
      },
      ...
    ]
  },
  day2: { /* same shape */ },
  ...
  materials: [                         // cross-day material index for the "all materials" tab
    { id: 'm-1', name: '...', type: '...', desc: '...' }
  ],
  quiz: [                              // optional: end-of-course assessment
    { id: 'q1', question: '...', options: [...], answer: 0, sourceUnit: 'day1.u-2' }
  ]
};

The Render Pipeline

index.html is one big <script> at the bottom. Its shape:

// 1. Utilities (top, ~50 lines)
const el = (tag, attrs, children) => { /* tiny DOM helper */ };
const store = {
  load() { /* read localStorage */ },
  save(state) { /* write localStorage */ },
  reset() { /* clear */ }
};

// 2. Render functions, each takes data → returns/appends DOM
function renderOverview(meta) { ... }
function renderSharedCase(case_) { ... }
function renderDay(day) { ... }
function renderUnit(unit, dayId) { ... }
function renderMaterials(materials) { ... }
function renderToolbox(tools) { ... }    // optional
function renderQuiz(quiz) { ... }        // optional

// 3. Sidebar + scrollspy + theme — see static-spa-interactions

// 4. Entry point
function init() {
  renderOverview(window.COURSE.meta);
  renderSharedCase(window.COURSE.sharedCase);
  for (const dayKey of ['day1', 'day2', 'day3', 'day4']) {
    renderDay(window.COURSE[dayKey]);
  }
  renderMaterials(window.COURSE.materials);
  renderQuiz(window.COURSE.quiz);
  // ... then interactivity wiring (see static-spa-interactions)
}
document.addEventListener('DOMContentLoaded', init);

Keep each render function pure: it receives data, it produces DOM. No reading from globals beyond its parameter. This makes adding a new section trivial.

The Material URL Router (getMaterialUrl)

The trickiest piece. The SPA needs to map a material's name and type to a real URL on disk. The router lives near the top of the script section:

function getMaterialUrl(name, type) {
  const base = 'course-package/materials';
  if (type === 'PDF 文件') {
    // PDFs trigger download instead of inline view
    if (name.includes('員工差勤')) return `${base}/pdf/員工差勤辦法.pdf`;
    if (name.includes('客訴SOP')) return `${base}/pdf/客訴處理SOP.pdf`;
    // ... one rule per PDF
    return null;  // unknown PDF → caller hides the link
  }
  // Other types open in new tab
  if (name.includes('FAQ')) return `${base}/FAQ官方版.md`;
  if (name.includes('差勤')) return `${base}/員工差勤辦法.md`;
  // ...
}

The three-place sync rule — when adding a material, update all of:

  1. Drop the file into course-package/materials/
  2. Add an entry to course-data.js:materials[] (and any unit's materials[])
  3. Add the name.includes(...) rule to getMaterialUrl()

Forgetting any one breaks the link. Consider adding a CI check that diffs filesystem vs. data vs. router.

The Task ID Lifecycle

// Save
function toggleTask(taskId) {
  const state = store.load();
  state.tasks[taskId] = !state.tasks[taskId];
  store.save(state);
  // re-render checkbox only, not whole page
}

// Load on render
function renderTask(task) {
  const state = store.load();
  const checked = !!state.tasks[task.id];
  return el('label', {}, [
    el('input', { type: 'checkbox', checked, onchange: () => toggleTask(task.id) }),
    task.text
  ]);
}

Never change task.id once published. The localStorage key tasks[task.id] is what survives across visits. Renaming wipes progress for every student.

Local Development

# Required: file:// blocks localStorage in Chrome — always serve via HTTP
npx serve .
# → http://localhost:3000

Add this to package.json:

{
  "scripts": {
    "serve": "npx serve ."
  }
}

Mention this prominently in any README. Double-clicking index.html produces a confusing "my progress doesn't save" bug that wastes hours.

Migration: Markdown → course-data.js

When porting an existing .md outline + content to course-data.js:

  1. Parse the outline first to get the day/unit skeleton.
  2. For each unit's content .md, extract tasks, prompts, materials references using grep-style passes (look for the marker patterns from course-content-authoring).
  3. Generate course-data.js as one big object literal. Don't try to make it pretty programmatically — let prettier/eslint format it, or just leave it as-is.
  4. Manually review: every unit ID in markdown should exist in course-data.js; the day count and hours should match meta.

When This Skill Hands Off

Tell the user:

  • "SPA scaffold is live. Run npm run serve and open http://localhost:3000."
  • "Next: invoke static-spa-interactions for progress persistence, sidebar, theme, RWD."
  • "Don't rename course-data.js paths or task IDs from this point — students' localStorage depends on them."

FAQ

What does the static-spa-conversion skill do?

Use this skill when you have structured course content (or any chapter-based dataset) in markdown form and need to turn it into a working interactive website — without picking a framework, without a build step. Triggers on phrases like "做成網頁", "轉成 SPA", "course-data.js", "render 函式", "把講義變網頁", "static site from markdown", "vanilla JS site", "no-framework site", "single-page app from markdown". The output is a vanilla HTML + JS single-page app that opens with npx serve and persists state in localStorage. Always invoke AFTER course-content-authoring (content stable), BEFORE static-spa-interactions (this skill produces the scaffold; interactions adorn it).

How do I install static-spa-conversion?

Run npx skills add https://github.com/kevintsai1202/teaching-site-skills --skill static-spa-conversion in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/static-spa-conversion/ (personal) or .claude/skills/static-spa-conversion/ (project).

Which AI agents can use static-spa-conversion?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is static-spa-conversion safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains static-spa-conversion?

It is published by kevintsai1202 in kevintsai1202/teaching-site-skills. It has 65 recorded installs.

More from kevintsai1202/teaching-site-skills

View all →

course-outline-design

kevintsai1202/teaching-site-skills

Use this skill when starting a new course / workshop / training program and you need to design its outline before any lecture content is written. Triggers on phrases like "規劃課程", "課程大綱", "幾天怎麼排", "學習目標", "workshop outline", "syllabus design", "course outline", "learning objectives", "課程總覽", or when the user has a topic and audience but no structure yet. This skill produces the skeleton (.md files) that all downstream stages — content authoring, SPA conversion, visual assets — depend on. Always invoke this BEFORE jumping into writing lecture notes or building a site.

course-ebook-publishing

kevintsai1202/teaching-site-skills

Use this skill ONLY AFTER a teaching site is feature-complete and stable, when the user wants to produce a printable / archivable / shareable version — typically a PDF ebook with cover, page numbers, table of contents, or a DOCX for editorial review. Triggers on phrases like "做電子書", "產 PDF", "ebook", "PDF ebook", "印給學員", "課程講義 PDF", "course handbook", "DOCX deliverable", "book-style layout", "build:ebook". Do NOT invoke during early site development — this is a downstream consumer that breaks if the site changes underneath. The skill produces PDF via Playwright page.pdf() and DOCX via pandoc, both from a single composed markdown source.

Docs & Writing77 installs

course-content-authoring

kevintsai1202/teaching-site-skills

Use this skill when an outline exists and you need to fill in the actual teaching content — lecture notes, sample materials (CSV / YAML / MD samples), quiz items, and any course-specific artifacts like prompt templates or worksheets. Triggers on phrases like "寫講義", "補素材", "出測驗題", "提示詞範本", "撰寫課程內容", "lecture notes", "course material", "quiz questions", "quiz authoring", "prompt templates". Always invoke AFTER course-outline-design is stable, BEFORE static-spa-conversion. This skill produces only the raw .md/.csv/.yaml artifacts — turning them into a website is the next stage's job.

course-corporate-edition

kevintsai1202/teaching-site-skills

Use this skill when an existing multi-day public-class teaching site needs to be condensed and re-packaged for a corporate in-house training — typically a half-day or one-day intensive (e.g. 4-day public class → 6-hour corporate). Triggers on phrases like "企業包班", "濃縮版", "客製化課程", "corporate edition", "intensive version", "in-house training", "single-file deliverable", "客戶端課程", "壓縮成一天", or when the user wants a single-folder zippable deliverable for a client. This skill builds on top of an existing site — picking units, condensing time allocation, embedding data into a single HTML, setting up asset fallback chains, and producing an offline-ready package.

teaching-site-design-system

kevintsai1202/teaching-site-skills

Use this skill whenever you're making visual / styling decisions on a teaching site or content-driven SPA — picking colors, fonts, badge styles, card layouts, hero treatments, dark mode tokens, or any "how should this look?" question. Triggers on phrases like "視覺風格", "設計系統", "色票", "字體", "暗色模式", "玻璃卡片", "提示詞徽章", "Day hero 怎麼設計", "design tokens", "design system", "color system", "glass cards", "typography", "look and feel", "視覺一致性", or any moment when the user evaluates aesthetics rather than behaviour. This is the cross-cutting visual authority — every stage (SPA, interactions, corporate edition, ebook) reads tokens from here so the brand stays coherent across formats.

teaching-site

kevintsai1202/teaching-site-skills

Use this skill as the main entry point whenever the user wants to build, plan, or evolve an interactive teaching website / course microsite / workshop landing page — from a blank slate, from existing course materials, or any state in between. Triggers on broad phrases like "做課程網站", "做教學網頁", "做工作坊網站", "把講義變網頁", "course microsite", "workshop site", "interactive lesson page", "multi-day curriculum website", "做一套課程". This skill is the router for the whole teaching-site pipeline (outline → content → SPA → interactions → visuals → corporate / ebook) and dispatches to the 10 specialised sub-skills as needed. Prefer this when the user's request is broad or unclear about which stage they're at — sub-skills (e.g. course-ebook-publishing) are still triggerable directly for stage-specific requests.

Popular marketing & seo skills

View category →

reddit-automation

flowkit-labs/skills

Find Reddit threads where people are genuinely asking for what you offer, then draft short, genuinely helpful replies — disclosing your affiliation honestly and naming your product only when it truly answers the question. Two moves: discovery — scan the right subreddits for real needs (recommendation asks, expressed pain, competitor mentions) and rank the few threads where you can actually help; drafting — write from real experience, respect each community's self-promo rules, and keep a human in the loop to review and post. This markets on Reddit the honest way: contribute value, disclose who you are, never astroturf. Distilled from the playbook behind doany.ai's Reddit agent. Triggers on "find reddit opportunities", "reddit marketing", "reddit automation", "reply on reddit for my product", "reddit community engagement", "reddit lead gen", or any ask to turn Reddit threads into genuine, disclosed marketing replies.

Marketing & SEO1.1M installs

twitter-automation

101-skills/superpowers

Automate Twitter/X with posting, engagement, and user management via inference.sh CLI. Apps: x/post-tweet, x/post-create (with media), x/post-like, x/post-retweet, x/dm-send, x/user-follow. Capabilities: post tweets, schedule content, like posts, retweet, send DMs, follow users, get profiles. Use for: social media automation, content scheduling, engagement bots, audience growth, X API. Triggers: twitter api, x api, tweet automation, post to twitter, twitter bot, social media automation, x automation, tweet scheduler, twitter integration, post tweet, twitter post, x post, send tweet

Marketing & SEO880K installs

twitter-automation

magentosh/superpowers

Automate Twitter/X with posting, engagement, and user management via inference.sh CLI. Apps: x/post-tweet, x/post-create (with media), x/post-like, x/post-retweet, x/dm-send, x/user-follow. Capabilities: post tweets, schedule content, like posts, retweet, send DMs, follow users, get profiles. Use for: social media automation, content scheduling, engagement bots, audience growth, X API. Triggers: twitter api, x api, tweet automation, post to twitter, twitter bot, social media automation, x automation, tweet scheduler, twitter integration, post tweet, twitter post, x post, send tweet

Marketing & SEO771.7K installs

twitter-automation

qu-skills/superpowers

Automate Twitter/X with posting, engagement, and user management via inference.sh CLI. Apps: x/post-tweet, x/post-create (with media), x/post-like, x/post-retweet, x/dm-send, x/user-follow. Capabilities: post tweets, schedule content, like posts, retweet, send DMs, follow users, get profiles. Use for: social media automation, content scheduling, engagement bots, audience growth, X API. Triggers: twitter api, x api, tweet automation, post to twitter, twitter bot, social media automation, x automation, tweet scheduler, twitter integration, post tweet, twitter post, x post, send tweet

Marketing & SEO564.3K installs

product-launch-video

heygen-com/hyperframes

Turn a product or marketing URL, pasted script, or brief into a product launch / promo video — SaaS promos, feature reveals, product demos, app and company launches. Use when the user wants to market, launch, promote, or reveal a product; the default for any commercial URL. Site tours / showcases of a website route here too — the brief carries the show-it-as-is intent. Unclear → /hyperframes.

Marketing & SEO538.7K installs

twitter-automation

skills-shell/superpowers

Automate Twitter/X with posting, engagement, and user management via inference.sh CLI. Apps: x/post-tweet, x/post-create (with media), x/post-like, x/post-retweet, x/dm-send, x/user-follow. Capabilities: post tweets, schedule content, like posts, retweet, send DMs, follow users, get profiles. Use for: social media automation, content scheduling, engagement bots, audience growth, X API. Triggers: twitter api, x api, tweet automation, post to twitter, twitter bot, social media automation, x automation, tweet scheduler, twitter integration, post tweet, twitter post, x post, send tweet

Marketing & SEO453.7K installs