ace-study-template
v0.3.1
Published
Pure renderSite(config) function + CLI that turn a site.config.json into a self-contained HTML study site. Runtime-agnostic: Node, Bun, Deno, Workers, browsers.
Maintainers
Readme
ace-study-template
Renders an Ace site.config.json into a single self-contained HTML study site.
Ships an ace-template CLI.
Part of Ace — open-source infrastructure for AI-generated interactive study content.
Install
npm install ace-study-template
# or
bun add ace-study-templateCLI
bunx ace-study-template path/to/site.config.json -o output/
# or
npx ace-study-template path/to/site.config.json -o output/Writes:
output/index.html— the deployable siteoutput/ace-components.js— bundled widgetsoutput/ace-styles.css— shared CSS
Then drag output/ onto Vercel / Netlify, or run:
npx vercel --prod output/Programmatic
renderSite(config, opts?) is a pure function. No filesystem, no network, no
globals. Safe to call from Node, Bun, Deno, Cloudflare Workers, the browser.
import { renderSite } from "ace-study-template";
import fs from "node:fs";
const config = JSON.parse(fs.readFileSync("site.config.json", "utf8"));
const html = renderSite(config, {
componentsBundleUrl: "./ace-components.js", // default
stylesUrl: "./ace-styles.css" // default
});
fs.writeFileSync("output/index.html", html);Use from a Cloudflare Worker (or any edge runtime)
Point componentsBundleUrl and stylesUrl at a CDN so the generated site
doesn't need co-located assets.
import { renderSite } from "ace-study-template";
export default {
async fetch(request, env) {
const config = await request.json();
const html = renderSite(config, {
componentsBundleUrl: "https://unpkg.com/[email protected]/index.js",
stylesUrl: "https://unpkg.com/[email protected]/styles.css",
});
// Write to R2, return as response body, etc.
await env.SITES.put(`${config.siteId}/index.html`, html, {
httpMetadata: { contentType: "text/html; charset=utf-8" },
});
return new Response(config.siteId);
},
};Contract
- Input: a
site.config.json-shaped object. Validated against thesite-config.schema.jsoninace-study-components; throws on invalid input or unknown widget types. - Output: a single complete HTML document string. UTF-8 safe.
- Determinism: identical input ⇒ identical output, provided
meta.generatedAtis fixed. WithoutgeneratedAt, aDate.now()cache-bust token is injected for dev-time convenience.
Config shape
See the schema at
ace-study-components/schemas/site-config.
High-level:
{
"version": "0.1",
"siteId": "course-code-yyyy-mm-dd",
"meta": { "course": "BME804", "title": "BME804 Exam Review" },
"sections": [
{
"id": "section-slug",
"title": "Section Title",
"subtopics": [
{
"id": "section-slug-topic",
"title": "Topic",
"widgets": [
{
"type": "slider-sandbox",
"id": "widget-id",
"props": { "...": "..." },
"source": "Lecture 3, p. 7"
}
]
}
]
}
]
}The optional source field on a widget renders as a small italic footnote
beneath the widget so students can verify claims against their own lectures.
License
MIT.
