Build a Worksheet
This tutorial walks you through building a Node.js script that generates a printable math worksheet using the StudyPlug API. By the end, you will have a standalone HTML file with 10 multiplication problems and an answer key.
Prerequisites
Section titled “Prerequisites”- Node.js 18+
- A terminal
1. Install the SDK
Section titled “1. Install the SDK”Create a new project and install the TypeScript SDK.
mkdir math-worksheet && cd math-worksheetnpm init -ynpm install studyplug2. Browse Skills
Section titled “2. Browse Skills”Before generating content, find the right skill slug. Let’s look for Grade 3 multiplication skills.
import { StudyPlug } from "studyplug";
const sp = new StudyPlug();
const { data } = await sp.skills.list({ grade: "grade-3", subject: "math",});
for (const skill of data.skills) { console.log(`${skill.slug} — ${skill.name}`);}Run it:
npx tsx browse.tsYou will see skills like multiply-by-3, multiply-by-6, and others. We will use multiply-by-6 for this worksheet.
3. Generate 10 Problems
Section titled “3. Generate 10 Problems”Now generate a batch of multiplication problems. Pass a seed so the worksheet is reproducible.
import { StudyPlug } from "studyplug";
const sp = new StudyPlug();
const { data } = await sp.generate({ skill: "multiply-by-6", grade: "grade-3", count: 10, seed: 101,});
console.log(`Generated ${data.items.length} problems`);console.log(`Answer key has ${data.answerKey.length} entries`);Each item in data.items is a ContentItem with structured fields like content.operand1, content.operand2, content.operator, and a corresponding entry in data.answerKey.
4. Format as a Printable HTML Page
Section titled “4. Format as a Printable HTML Page”Build a simple HTML template that renders the problems and looks clean when printed.
import { StudyPlug } from "studyplug";import { writeFileSync } from "node:fs";
const sp = new StudyPlug();
const { data } = await sp.generate({ skill: "multiply-by-6", grade: "grade-3", count: 10, seed: 101,});
const problemRows = data.items .map((item, i) => { const c = item.content; if (c.type !== "arithmetic") return ""; const num = i + 1; return `<tr> <td>${num}.</td> <td>${c.operand1} ${c.operator} ${c.operand2} = ______</td> </tr>`; }) .join("\n");
const answerRows = data.answerKey .map((entry, i) => { return `<li>${i + 1}. ${entry.answer}</li>`; }) .join("\n");
const html = `<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" /> <title>Multiplication Worksheet — Grade 3</title> <style> body { font-family: Arial, sans-serif; max-width: 700px; margin: 40px auto; } h1 { text-align: center; font-size: 24px; } table { width: 100%; border-collapse: collapse; margin: 24px 0; } td { padding: 12px 8px; font-size: 20px; } .answer-key { margin-top: 48px; border-top: 2px dashed #ccc; padding-top: 16px; } .answer-key h2 { font-size: 16px; color: #666; } .answer-key li { font-size: 14px; color: #666; } @media print { .answer-key { page-break-before: always; } } </style></head><body> <h1>Multiplication Practice</h1> <p>Name: _________________________ Date: _____________</p> <table>${problemRows}</table> <div class="answer-key"> <h2>Answer Key</h2> <ol>${answerRows}</ol> </div></body></html>`;
writeFileSync("worksheet.html", html);console.log("Wrote worksheet.html — open it in a browser and print!");5. Run It
Section titled “5. Run It”npx tsx worksheet.tsOpen worksheet.html in your browser and hit Ctrl+P (or Cmd+P) to print. The answer key appears on a separate page thanks to the page-break-before CSS rule.
What You Built
Section titled “What You Built”- Browsed the StudyPlug catalog to find a skill slug
- Generated 10 deterministic multiplication problems with a seed
- Rendered them as a printable HTML worksheet with an answer key
Variations to Try
Section titled “Variations to Try”- Change the
seedto get a different set of problems with the same skill - Swap
multiply-by-6for any skill slug from the catalog - Increase
countup to 50 for longer worksheets - Use
renderHints.print.columnsfrom each item to arrange problems in a two-column layout
Using with Next.js App Router
Section titled “Using with Next.js App Router”If you are building with Next.js 14+ (App Router), here is how to integrate the API into a Server Component and Route Handler.
Route Handler (API proxy)
Section titled “Route Handler (API proxy)”Create app/api/worksheet/route.ts to proxy requests through your backend:
import { StudyPlug } from "studyplug";import { NextResponse } from "next/server";
const sp = new StudyPlug({ apiKey: process.env.STUDYPLUG_API_KEY, // optional, for higher rate limits});
export async function POST(request: Request) { const { skill, grade, count, seed } = await request.json();
const { data } = await sp.generate({ skill, grade, count: count ?? 10, seed, });
return NextResponse.json(data);}Server Component
Section titled “Server Component”Fetch skills and generate content directly in a Server Component:
import { StudyPlug } from "studyplug";
const sp = new StudyPlug();
export default async function WorksheetPage() { const { data } = await sp.generate({ skill: "multiply-by-6", grade: "grade-3", count: 10, seed: 101, });
return ( <main> <h1>Multiplication Practice</h1> <ol> {data.items.map((item, i) => { if (item.content.type !== "arithmetic") return null; const c = item.content; return ( <li key={i}> {c.operand1} {c.operator} {c.operand2} = ______ </li> ); })} </ol> </main> );}Next Steps
Section titled “Next Steps”- Build a Quiz — turn ContentItems into an interactive digital quiz
- Content Items — understand the full ContentItem structure
- Deterministic Generation — learn how seeds work
- SDK Reference — explore all SDK methods