AI generated lesson plans for teachers: from plan to student page

A lesson plan from ChatGPT, Claude or Gemini is a document for the teacher. Ask for a page instead, check it, and send students one link that opens in any browser.

An AI-generated lesson plan is written for you: objective, materials, timings. Students need something different, a page they can tap through. Ask the AI for a student-facing HTML page, check it, and share it as one link.

The reason to bother is access. One guide to Claude's artifact tool puts it this way: "Since K–12 students can't directly access Claude, teachers must use workarounds like hosting artifacts on LMS platforms or teacher websites."

A link is the shortest of those workarounds. Here is a page of the kind the AI can write from a plan. Tap the stages, answer the quick check and try the checklist, the way a student would.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>The Water Cycle - student page</title>
<style>
  * { box-sizing: border-box; }
  body { margin: 0; font-family: system-ui, sans-serif; background: #f3f6fb; color: #1d2330; line-height: 1.5; }
  header { background: linear-gradient(135deg, #1d4ed8, #0ea5e9); color: #fff; padding: 22px 18px; }
  header h1 { margin: 0 0 4px; font-size: 26px; }
  header p { margin: 0; opacity: .9; font-size: 14px; }
  main { max-width: 640px; margin: 0 auto; padding: 14px; }
  section { background: #fff; border-radius: 12px; padding: 16px; margin-bottom: 14px; box-shadow: 0 1px 4px rgba(0,0,0,.08); }
  h2 { margin: 0 0 8px; font-size: 18px; }
  .num { display: inline-block; width: 26px; height: 26px; line-height: 26px; text-align: center; border-radius: 50%; background: #1d4ed8; color: #fff; font-size: 14px; margin-right: 6px; }
  .goal { border-left: 5px solid #16a34a; }
  button { font: inherit; cursor: pointer; border: 1px solid #c7d2e5; background: #f8faff; border-radius: 8px; padding: 9px 14px; }
  button:hover { background: #eaf1ff; }
  .stages { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0; }
  .stages button.done { background: #dcfce7; border-color: #16a34a; }
  .stages button.wrong { background: #fee2e2; border-color: #dc2626; }
  .msg { min-height: 22px; font-weight: 600; }
  .ok { color: #15803d; } .bad { color: #b91c1c; }
  fieldset { border: 0; padding: 0; margin: 0 0 12px; }
  legend { font-weight: 600; margin-bottom: 4px; }
  label { display: block; padding: 4px 0; }
  .fb { font-size: 14px; margin-top: 2px; }
  ul.links { padding-left: 18px; margin: 6px 0; }
  details summary { cursor: pointer; color: #1d4ed8; }
  .check label { display: flex; gap: 8px; align-items: flex-start; }
</style>
</head>
<body>
<header>
  <h1>The Water Cycle</h1>
  <p>Grade 5 science &middot; about 40 minutes &middot; Ms. Rivera's class (sample)</p>
</header>
<main>
  <section class="goal">
    <h2>Today's goal</h2>
    <p>By the end of this page you can name the four stages of the water cycle and put them in order.</p>
  </section>

  <section>
    <h2><span class="num">1</span>Warm-up</h2>
    <p>Where does a puddle go after the rain stops?</p>
    <details><summary>Show a hint</summary><p>Think about what the sun does to water.</p></details>
  </section>

  <section>
    <h2><span class="num">2</span>Put the stages in order</h2>
    <p>Tap the stages in the order they happen. Start with the first.</p>
    <div class="stages" id="stages"></div>
    <div class="msg" id="orderMsg"></div>
    <button id="resetOrder" type="button">Start again</button>
  </section>

  <section>
    <h2><span class="num">3</span>Quick check</h2>
    <form id="quiz">
      <fieldset data-answer="b">
        <legend>1. What turns liquid water into vapor?</legend>
        <label><input type="radio" name="q1" value="a"> Freezing</label>
        <label><input type="radio" name="q1" value="b"> Evaporation</label>
        <label><input type="radio" name="q1" value="c"> Collection</label>
        <div class="fb"></div>
      </fieldset>
      <fieldset data-answer="c">
        <legend>2. Clouds form when vapor cools. This is called:</legend>
        <label><input type="radio" name="q2" value="a"> Precipitation</label>
        <label><input type="radio" name="q2" value="b"> Evaporation</label>
        <label><input type="radio" name="q2" value="c"> Condensation</label>
        <div class="fb"></div>
      </fieldset>
      <fieldset data-answer="a">
        <legend>3. Rain, snow and hail are all kinds of:</legend>
        <label><input type="radio" name="q3" value="a"> Precipitation</label>
        <label><input type="radio" name="q3" value="b"> Condensation</label>
        <label><input type="radio" name="q3" value="c"> Evaporation</label>
        <div class="fb"></div>
      </fieldset>
      <button type="submit">Check my answers</button>
      <div class="msg" id="score"></div>
    </form>
  </section>

  <section>
    <h2><span class="num">4</span>Go further</h2>
    <p>Replace these sample links with your own videos, readings or class pages.</p>
    <ul class="links">
      <li><a href="https://example.com/water-cycle-video" target="_blank" rel="noopener">Watch: the water cycle in 3 minutes</a></li>
      <li><a href="https://example.com/water-cycle-reading" target="_blank" rel="noopener">Read: a short passage with questions</a></li>
    </ul>
  </section>

  <section class="check">
    <h2><span class="num">5</span>Before you leave</h2>
    <label><input type="checkbox"> I can name the four stages.</label>
    <label><input type="checkbox"> I can explain why puddles dry up.</label>
  </section>
</main>

<script>
  // Step 2: tap the stages in order
  const correct = ['Evaporation', 'Condensation', 'Precipitation', 'Collection'];
  const shuffled = ['Precipitation', 'Evaporation', 'Collection', 'Condensation'];
  const box = document.getElementById('stages');
  const orderMsg = document.getElementById('orderMsg');
  let next = 0;

  function buildStages() {
    box.innerHTML = '';
    next = 0;
    orderMsg.textContent = '';
    shuffled.forEach((name) => {
      const b = document.createElement('button');
      b.type = 'button';
      b.textContent = name;
      b.addEventListener('click', () => {
        if (b.classList.contains('done')) return;
        if (name === correct[next]) {
          next++;
          b.classList.add('done');
          b.textContent = next + '. ' + name;
          if (next === correct.length) {
            orderMsg.className = 'msg ok';
            orderMsg.textContent = 'Correct order. Well done!';
          }
        } else {
          b.classList.add('wrong');
          orderMsg.className = 'msg bad';
          orderMsg.textContent = 'Not yet. Try another stage.';
          setTimeout(() => b.classList.remove('wrong'), 600);
        }
      });
      box.appendChild(b);
    });
  }
  document.getElementById('resetOrder').addEventListener('click', buildStages);
  buildStages();

  // Step 3: the quiz is checked inside the page, nothing is sent anywhere
  document.getElementById('quiz').addEventListener('submit', (e) => {
    e.preventDefault();
    let score = 0;
    document.querySelectorAll('#quiz fieldset').forEach((fs) => {
      const picked = fs.querySelector('input:checked');
      const fb = fs.querySelector('.fb');
      if (picked && picked.value === fs.dataset.answer) {
        score++;
        fb.textContent = 'Correct';
        fb.className = 'fb ok';
      } else {
        fb.textContent = picked ? 'Not quite. Look at step 2 again.' : 'Pick an answer.';
        fb.className = 'fb bad';
      }
    });
    const s = document.getElementById('score');
    s.className = 'msg ' + (score === 3 ? 'ok' : 'bad');
    s.textContent = 'You got ' + score + ' of 3.';
  });
</script>
</body>
</html>
A student page made from one lesson plan: warm-up, an ordering activity, a quick check, links and a checklist.

The links in the demo point to example.com. Replace them with your own videos, readings or class pages.

The same lesson twice: the plan is for the teacher, the page is for the student.
The same lesson twice: the plan is for the teacher, the page is for the student.

Make it with AI

Paste your plan into ChatGPT, Claude or Gemini with a prompt like this. Fill in the square brackets.

I am a [grade] [subject] teacher. Turn the lesson plan below
into ONE self-contained HTML file for my students.

The page needs:
- a title and a goal in words a [grade] student understands
- numbered steps (warm-up, activity, quick check, wrap-up)
- one interactive activity, such as putting steps in order
- 3 quiz questions that show feedback on the page
- a list of links, using example.com as placeholders
- a checklist for the end of the lesson

Rules: inline CSS and JavaScript only. No outside images, fonts
or libraries. Do not store or send any data. It must work on a
phone 390 pixels wide.

Lesson plan:
[paste your plan here]

Leave student names out of the prompt. The page does not need them.

Then check the result before anyone else sees it:

  • Facts and answers. Read the quiz and the answer key. The AI can sound sure and be wrong.
  • Reading level. Read the instructions aloud. Ask the AI to simplify anything you would have to explain.
  • Links. Swap every placeholder for a real address and open each one.
  • Phone. Open it on a phone. If a button is tiny or text runs off the edge, tell the AI exactly what to fix.
From a chat to a link: ask, check, paste, send.
From a chat to a link: ask, check, paste, send.

Copy the HTML the AI gave you, paste it into a NOS document and choose Create share link. HTML to link walks through it. The page renders as written and its scripts run, so the ordering activity and the quiz work.

Anyone with the link can open it in a browser, on a phone too, without an account. They can use it but cannot edit it. If you find a typo later, edit the code and the same link shows the new version.

Some things are blocked on a shared page: sending a form to a server, images from other websites, iframes and fetch calls to other sites. Quiz scoring inside the page works. The score appears on the student's screen and goes nowhere else.

For the ChatGPT and Claude specifics, see sharing ChatGPT HTML output and turning a Claude artifact into a link.

Ways to share the page compared

An HTML file against a link, as a student opens it on a phone.
An HTML file against a link, as a student opens it on a phone.
Way to share What students do Watch for
Send the .html file Download it and find an app to open it May show as code on a phone, and copies pile up
Link in an email Tap the link Students must find the email again
Link in Google Classroom Open the assignment or material, tap the link Needs your Classroom access
Link in a Canvas module Open the module item Needs permission to edit the course
QR code on paper Scan it with a phone camera Needs a camera on the student's device

Google Classroom Help says you can attach a link to an assignment, and on the Classwork page you can create a Material post and add a link to it. As of October 2026, that is how both are described.

Canvas lets an instructor add an External URL as a module item. A checkbox decides whether the link opens in a new browser tab, and when it is ticked Canvas shows the page to students outside of Canvas.

Your school's settings decide what you can see in either tool. If an option is missing, ask whoever administers it.

For paper, turn the link into a QR code. To place the page inside a site you already have, read HTML on Google Sites.

One lesson or a whole unit

A plan often covers several days. Ask the AI for tabs, one per day, so students see only today's tasks and one link covers the unit.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Persuasive writing - 3-day unit</title>
<style>
  * { box-sizing: border-box; }
  body { margin: 0; font-family: system-ui, sans-serif; background: #fbf7f0; color: #26211a; line-height: 1.5; }
  header { padding: 18px 16px 8px; max-width: 640px; margin: 0 auto; }
  header h1 { margin: 0; font-size: 24px; }
  header p { margin: 2px 0 0; color: #6b5f4e; font-size: 14px; }
  .tabs { display: flex; gap: 6px; max-width: 640px; margin: 8px auto 0; padding: 0 16px; }
  .tabs button { flex: 1; font: inherit; font-weight: 600; cursor: pointer; padding: 10px 6px; border: 1px solid #e3d8c4; border-bottom: 0; border-radius: 10px 10px 0 0; background: #f1e8d6; color: #6b5f4e; }
  .tabs button[aria-selected="true"] { background: #fff; color: #9a3412; }
  .panel { max-width: 640px; margin: 0 auto; background: #fff; border: 1px solid #e3d8c4; border-radius: 0 0 12px 12px; padding: 16px; margin-bottom: 20px; }
  .panel[hidden] { display: none; }
  h2 { margin: 0 0 6px; font-size: 18px; }
  .task { display: flex; gap: 10px; align-items: flex-start; padding: 8px 0; border-bottom: 1px solid #f0e9da; }
  .task:last-of-type { border-bottom: 0; }
  .task input { margin-top: 5px; }
  .task.done span { text-decoration: line-through; color: #8a7e6b; }
  .timer { display: flex; align-items: center; gap: 10px; margin-top: 12px; padding: 10px 12px; background: #fff4e5; border-radius: 10px; flex-wrap: wrap; }
  .timer output { font: 700 24px ui-monospace, Consolas, monospace; min-width: 70px; }
  .timer button { font: inherit; cursor: pointer; border: 1px solid #e3b97a; background: #fff; border-radius: 8px; padding: 6px 12px; }
  a { color: #9a3412; }
  .tip { background: #eef7ee; border-left: 4px solid #16a34a; padding: 8px 12px; border-radius: 6px; margin: 10px 0 0; font-size: 14px; }
</style>
</head>
<body>
<header>
  <h1>Persuasive Writing</h1>
  <p>Grade 7 English &middot; 3 days &middot; sample unit</p>
</header>

<div class="tabs" role="tablist">
  <button role="tab" aria-selected="true" data-tab="d1">Day 1</button>
  <button role="tab" aria-selected="false" data-tab="d2">Day 2</button>
  <button role="tab" aria-selected="false" data-tab="d3">Day 3</button>
</div>

<div class="panel" id="d1" role="tabpanel">
  <h2>Day 1: Find the argument</h2>
  <label class="task"><input type="checkbox"><span>Read the sample letter to the principal.</span></label>
  <label class="task"><input type="checkbox"><span>Underline the claim in one color and the reasons in another.</span></label>
  <label class="task"><input type="checkbox"><span>Write one sentence: what does the writer want?</span></label>
  <p>Sample text: <a href="https://example.com/sample-letter" target="_blank" rel="noopener">Letter to the principal</a></p>
  <div class="timer" data-seconds="600"><span>Reading time</span><output>10:00</output><button type="button" data-act="go">Start</button><button type="button" data-act="reset">Reset</button></div>
</div>

<div class="panel" id="d2" role="tabpanel" hidden>
  <h2>Day 2: Plan your own</h2>
  <label class="task"><input type="checkbox"><span>Pick a topic from the list your teacher gave you.</span></label>
  <label class="task"><input type="checkbox"><span>Write your claim and three reasons.</span></label>
  <label class="task"><input type="checkbox"><span>Swap plans with a partner and give one question.</span></label>
  <div class="tip">Tip: a good reason answers the question "why should I agree?"</div>
  <div class="timer" data-seconds="900"><span>Planning time</span><output>15:00</output><button type="button" data-act="go">Start</button><button type="button" data-act="reset">Reset</button></div>
</div>

<div class="panel" id="d3" role="tabpanel" hidden>
  <h2>Day 3: Write and check</h2>
  <label class="task"><input type="checkbox"><span>Write your letter, using your plan from Day 2.</span></label>
  <label class="task"><input type="checkbox"><span>Read it aloud once and fix one sentence.</span></label>
  <label class="task"><input type="checkbox"><span>Hand it in using the way your teacher showed you.</span></label>
  <p>Checklist: <a href="https://example.com/writing-checklist" target="_blank" rel="noopener">Persuasive writing checklist</a></p>
  <div class="timer" data-seconds="1500"><span>Writing time</span><output>25:00</output><button type="button" data-act="go">Start</button><button type="button" data-act="reset">Reset</button></div>
</div>

<script>
  // Tabs: show one day at a time
  const tabs = document.querySelectorAll('.tabs button');
  tabs.forEach((t) => t.addEventListener('click', () => {
    tabs.forEach((x) => x.setAttribute('aria-selected', x === t));
    document.querySelectorAll('.panel').forEach((p) => { p.hidden = p.id !== t.dataset.tab; });
  }));

  // Strike through finished tasks
  document.querySelectorAll('.task input').forEach((c) =>
    c.addEventListener('change', () => c.closest('.task').classList.toggle('done', c.checked)));

  // One countdown per day
  document.querySelectorAll('.timer').forEach((box) => {
    const out = box.querySelector('output');
    const total = Number(box.dataset.seconds);
    let left = total, id = null;
    const show = () => {
      out.textContent = String(Math.floor(left / 60)).padStart(2, '0') + ':' + String(left % 60).padStart(2, '0');
    };
    box.querySelector('[data-act="go"]').addEventListener('click', (e) => {
      if (id) { clearInterval(id); id = null; e.target.textContent = 'Start'; return; }
      e.target.textContent = 'Pause';
      id = setInterval(() => {
        left--; show();
        if (left <= 0) { clearInterval(id); id = null; e.target.textContent = 'Start'; out.textContent = 'Time!'; }
      }, 1000);
    });
    box.querySelector('[data-act="reset"]').addEventListener('click', () => {
      clearInterval(id); id = null; left = total; show();
      box.querySelector('[data-act="go"]').textContent = 'Start';
    });
  });
</script>
</body>
</html>
A three-day unit on one page. Each day has tasks to tick off, a link and a countdown timer.

Ticks in this page are not saved for visitors, so a student who reloads starts the day again. Say so in your instructions, or keep long work on paper or in your class platform.

If the page is mostly questions, this guide to HTML quizzes shows how to ask for scoring and feedback.

When it does not work

Symptom Cause Fix
Students see code, not a page They received the file, not the link Send the NOS share link instead
An image is missing It was loaded from another website Ask the AI for an inline SVG or CSS drawing
A video box is empty It uses an iframe, which is blocked Link to the video instead of embedding it
Quiz answers are not collected The page cannot send a form to a server Use your platform for the graded part
Text runs off a phone screen No mobile layout Ask for a layout that works at 390 pixels wide
Students see the old version They have an old tab open Ask them to reload the page

More on why a file will not show up on a phone: opening an HTML file on a phone.

Questions people ask

Do students need an account to open the page?

No. A NOS share link opens in the browser, on a phone too, without an account. Students do not need a ChatGPT, Claude or Gemini login either, because they only see the finished page.

Can I see who opened the page or what score they got?

No. NOS does not show who opened a link, and a quiz score stays on the student's own screen. If you need marks, use your class platform's assignment for the part you grade and use the page for the practice.

Can I fix a mistake after I have sent the link?

Yes. Edit the code in your NOS document and the same link shows the new version. Students who reload the page see the fix, so you do not have to send anything again.

Will the page remember a student's answers?

No. Ticks and answers a visitor makes are not saved, so reloading the page starts fresh. Only the owner's changes made in View mode are saved. A form that tries to send data to a server is blocked.

Which AI tool should I use?

Any chat that can write a full HTML page works. Paste the same prompt into ChatGPT, Claude or Gemini and compare. Whichever you use, read the result yourself before students do.

Keep reading