Tutorials
Build an educational explainer from a JSON lesson template
Render a 30-second educational explainer from a complete JSON lesson template. Repeat teaching points, hide an optional example and download the MP4 with Node.js.
By Mina RamzyPublished Updated
A useful educational video starts with one thing the learner should understand. A reusable template keeps the presentation consistent while you change the lesson: its title, teaching points, worked example and takeaway.
This tutorial turns a JSON lesson about HTTPS into a 30-second, six-scene MP4. You will run a complete Node.js example, check the resolved lesson without spending credits, then render and download it. The design is intentionally silent, so the teaching text carries the lesson. No recording or hosted source media is needed.
What you need
Use Node.js 22 or newer, npm and a Zvid account. At app.zvid.io/api-keys, click Create API key, enter a name such as Educational lesson, then click Create API Key. In the result dialog, click Copy API key and save the complete value before clicking Done. Keep it private; the full key is shown only once. The API key guide provides optional help.
The supplied 1280 × 720 video requires 30 render credits. Validation does not consume render credits or create a render job. The validation command checks the current limits and returns the estimate before you submit. Credit calculation depends on output duration and pixel dimensions.
The download includes the lesson, template, runnable script and offline tests. It does not contain an API key or the finished MP4. The sample runs without installing third-party Node.js dependencies or saving a template to your account.
1. Set up the example
Extract the ZIP and open a terminal inside educational-explainer-json. If you use GitHub, open examples/educational-explainer-json in your checkout. Run:
node --version
npm ci
npm run check
npm test
Copy .env.example to .env. In PowerShell, run Copy-Item .env.example .env; on macOS or Linux, use cp .env.example .env. Open .env in a text editor and replace the placeholder below with your key:
ZVID_API_KEY=YOUR_ZVID_API_KEY
MAX_RENDER_CREDITS=30
The npm commands load .env automatically. Keep the 30-credit ceiling for this sample. If PowerShell blocks npm.ps1, use npm.cmd in place of npm. Do not paste your key into the lesson JSON, a browser page or source control.
2. Keep the lesson separate from the design
Open data/lesson.json. It holds the facts and wording that change between lessons. data/template.json holds the positions, colors, type sizes and scene durations.
The learning goal is to recognize three protections in an HTTPS connection: encryption, server authentication and integrity. These are deliberately short teaching points, not a complete explanation of TLS. A secure connection also does not prove that a shop is honest. The MDN introduction to TLS provides the background for the sample.
View the complete lesson record
{
"course": "WEB BASICS",
"title": "How HTTPS protects a request",
"goal": "Recognize three protections in one connection.",
"points": [
{
Collapse example
{
"course": "WEB BASICS",
"title": "How HTTPS protects a request",
"goal": "Recognize three protections in one connection.",
"points": [
{
"heading": "Encrypt",
"body": "TLS encrypts data between the browser and server."
},
{
"heading": "Verify",
"body": "A valid certificate helps the browser authenticate the server."
},
{
"heading": "Detect changes",
"body": "Integrity checks detect data altered in transit."
}
],
"showExample": true,
"exampleTitle": "Secure checkout",
"exampleBody": "Before sending payment data, the browser establishes a verified, encrypted connection.",
"takeaway": "Encryption + authentication + integrity.",
"limitation": "A secure connection does not prove that a shop is honest."
}
The example checks the lesson before sending it to Zvid. It accepts one to three points, a title up to 56 characters, point headings up to 24 characters and point bodies up to 90 characters. These are this example's layout rules, not general Zvid limits. Each text field must be nonempty plain text without HTML or template braces. showExample must be a Boolean, true or false.
The mapper adds a display number to each point in order. The first input, {"heading":"Encrypt","body":"TLS encrypts data between the browser and server."}, becomes the same object with "number":"01". The visible card shows 01, Encrypt and that exact explanation.
How one scene becomes three cards
The template declares safe defaults in variables. Its placeholders, such as {{title}}, receive the current lesson values. The complete design is in the download; these are the fields that make its teaching-point scene repeat:
{
"id": "point",
"iterate": "points",
"iterateAs": "point",
"duration": 5
}
Inside that scene, the three text layers read {{point.number}}, {{point.heading}} and {{point.body}}. Zvid's scene iteration creates one scene for each object in points, in array order. It creates three cards inside one video, not three separate files.
The worked-example scene uses "condition": "{{showExample}}". When the flag is false, that scene is removed before rendering. The remaining scenes keep their order.
3. Resolve the template and check the estimate
Run:
npm start
The script sends the design and lesson variables to POST https://api.zvid.io/api/render/validate/api-key, authenticated with the x-api-key header. Validation and estimation resolve the template and check the request against the account's limits. This step does not render a video.
For the unchanged sample, expect:
6 scenes, 30 seconds. Estimate: 30 credits.
Saved out/resolved-project.json. No render submitted.
Open out/resolved-project.json and check the copy and scene order: opening, point-1, point-2, point-3, example, takeaway. out/validation.json contains the estimate and any warnings. The script stops if text, order, count or duration disagrees with the supplied lesson, or if the API reports a warning.
This template has no overlapping transitions, so its scene durations add directly:
| Part | Duration |
|---|---|
| Opening | 4 seconds |
| Three teaching points | 5 seconds each |
| Worked example | 6 seconds |
| Takeaway | 5 seconds |
| Total | 30 seconds |
To check the optional branch, set showExample to false in data/lesson.json and run npm start again. Expect five scenes, 24 seconds and a 24-credit estimate. Set it back to true and validate again before rendering the same six-scene video shown above. A resolved JSON file proves the data mapping; it is not a visual preview or a finished video.
4. Render once and save the MP4
Run:
npm run render
This command validates again, checks the estimate against MAX_RENDER_CREDITS, and submits the exact resolved project to POST /api/render/api-key. This step spends render credits. It saves the job ID in out/run.json before tracking the job, then downloads out/https-lesson.mp4 when rendering completes.
Open the MP4 and watch all six scenes. Confirm the longest explanation is readable, the numbered cards follow the input order, the worked example appears and the takeaway remains visible long enough to read. The silent output should match the video at the start of this article.
Rendering is asynchronous. A submission response means the job was accepted; progress: 100 alone does not mean the file is ready. The script waits for state: "completed" and a usable output URL, with a ten-minute waiting limit. See the render lifecycle for the request and response details.
If waiting or downloading stops
Run npm run resume to track the saved job and download its result without submitting another render. A local timeout does not cancel a job that is still running.
If submission stopped before the script saved an ID, open Renders at app.zvid.io, identify the existing job and run:
npm run resume -- --job-id YOUR_JOB_ID
Do not immediately run the render command again. The example writes an attempt marker before submission and blocks a second paid request from that output folder. A missing response does not prove that Zvid received nothing. A failed job reports its reason; expired output needs a new deliberate render rather than another download attempt. For help with a job, use https://zvid.io/contact.
Reuse the template for another lesson
Change the facts in data/lesson.json, leaving the layout in data/template.json intact. Write one objective and one claim per point. Keep the takeaway useful on its own, and use the limitation field for a boundary learners should remember.
Before making another video, check the previous job and rename out to preserve its record. Run npm start, inspect the new resolved lesson and estimate, then deliberately run npm run render. Review every new result before distributing it. Copy limits reduce the risk of overflow; they do not guarantee that every sentence or language fits this design.
If you change the template's durations, transitions or scene structure, update expectedTimeline in src/lesson.js and the tests too. Otherwise the script will correctly reject a result that differs from its expected structure.
For spoken instruction, prepare a final recording, adjust the scene timing to that recording and add matching captions. This sample does not generate narration or transcribe audio. The faceless-video walkthrough covers a narrated composition, while template validation develops a broader set of boundary checks.
Frequently asked questions
Can I change the number of teaching points in this educational video template?
Yes. This example accepts one to three objects in points, and Zvid repeats the teaching-point scene once per object. Changing the count changes the duration and credit estimate. Run npm start after each edit and inspect the resolved order before rendering.
Does this JSON template generate narration or subtitles automatically?
No. The supplied educational example creates a silent video from visible teaching text. Narration requires a separate recording, and subtitles require text and timing matched to that recording. Adding either also requires a new timing and playback review.
Does validating the lesson consume Zvid credits?
No. npm start calls Zvid's validation endpoint without creating a render job or consuming render credits. npm run render submits a paid render after checking the current estimate. The unchanged 30-second sample requires 30 credits.
Do I need to save a template in my Zvid account before running this example?
No. The example submits data/template.json as an inline payload with request-level variables. You can reuse that local template file without creating a stored template. A stored template ID is a separate option when you want to manage the design through your account.
How do I hide the worked example without leaving an empty scene?
Set showExample to false in data/lesson.json. The template's condition removes the entire example scene before rendering. With the three supplied points, the result has five scenes and lasts 24 seconds.