---
name: images
description: "Find, search, or generate image content for Canvas course pages — search-first for real content, generate for custom visuals."
---

# Images Skill

> **Plugin**: ASU Canvas Course Builder
> **Related**: visual-builder (SVG diagrams/infographics), course-build (Phase 2.5), resource-discovery

## Purpose

Find, vet, generate, and embed images for Canvas course pages. Combines CC-licensed image search (OpenVerse, Wikimedia, Smithsonian, NASA, Library of Congress) with AI generation (Nano Banana, Google Imagen 4) into a single workflow. Prioritizes accuracy, accessibility, and legal safety.

## Search-First Principle

**For scientific, biological, medical, historical, or real-world imagery, ALWAYS search before generating.** AI-generated scientific content may be inaccurate — a real photograph or vetted illustration is almost always better for factual content.

- Medical/anatomical illustrations: **search only** (never generate)
- Historical photographs: **search only** (never generate)
- Data visualizations (charts, graphs): **search only** or use `visual-builder`
- Maps presented as factual: **search only** (never generate)
- Images of real people: **search only** (never generate)
- Real-world examples, lab equipment, field photos: **search first**, generate only if nothing found
- Abstract concepts, process flows, branded graphics, custom diagrams: **generate directly**

When a search yields poor results for factual content, tell the user explicitly before offering to generate. Never silently switch from search to generation.

---

## Mode Routing

| User says | Mode |
|---|---|
| "Find images for Module 3" / "Search for a photo of..." | **Mode 1: Search** |
| "Generate an illustration" / "Create an image of..." | **Mode 2: Generate** |
| "Add images to my course" / "I need visuals" (ambiguous) | **Mode 3: Course-Wide Scan** |
| "Images for all modules" / "Suggest images across the course" | **Mode 3: Course-Wide Scan** |

If the user's intent is ambiguous between search and generate, apply the Search-First Principle: if the subject is real-world or factual, default to Mode 1. If the subject is abstract or custom, default to Mode 2.

---

## Required Inputs

| Input | Source |
|---|---|
| Module context (topics, objectives) | `course-config.json` |
| Target page and placement | User specifies or inferred from context |
| Canvas credentials | `.env` |

## Prerequisites

- `course-config.json` exists with module structure defined
- Canvas credentials configured
- Proxy available at `asu-plugin-api.vercel.app` (search and generation endpoints)

## Standards Reference

Read `standards/image-generation-guidelines.md` for the full Search-First Principle, prompt engineering rules, vetting checklist, alt text requirements, and embedding standards.

---

## Mode 1: Search

Search for CC-licensed images from vetted educational sources and embed them in Canvas pages. Use this mode when the image must be factually accurate, historically real, or from a vetted source.

### Step 1-S: Determine Scope

Present an `AskUserQuestion`:

**Question**: "What images are you looking for?"

| Label | Description |
|---|---|
| **Specific image** | I know what I need — let me describe it |
| **Images for a module** | Find images for all pages in a specific module |
| **Course-wide scan** | Suggest images for every module that could benefit from visuals |

- **Specific image**: Proceed to Step 3-S with the user's description.
- **Images for a module**: Ask which module, then read `course-config.json` for context. Proceed to Step 2-S.
- **Course-wide scan**: Switch to Mode 3.

### Step 2-S: Analyze Module Context

For the target module, extract from `course-config.json`:
- Module title and topics
- Learning objectives (with Bloom's levels)
- Existing resources
- Pages that exist for this module

Identify image opportunities per page:
- **Overview**: 0-1 contextual image (real-world connection)
- **Lesson**: 1-3 instructional images (concept illustrations, diagrams, real examples)
- **Prepare to Learn**: 0-1 contextual image
- **Other pages**: Rarely need images (assessments, guided practice)

For each opportunity, draft a search query aligned to the learning objective.

### Step 3-S: Search for Images

**Audience default (always apply):** vet every candidate for a college audience. When an image shows people, prefer adult college learners, diverse across race, age, gender, and ability. Reject children, K-12 classrooms, and juvenile settings unless the course topic explicitly requires them. When searching for learner imagery, add adult/college/diversity terms to the query, for example `"adult learner"`, `"college student"`, `"working adult"`, `"diverse students"`, `"online study"`. See `standards/image-generation-guidelines.md` Audience & Representation.

For each image need, call the proxy search endpoint:

```bash
# Auth headers piped via stdin (not argv) so CANVAS_TOKEN never appears in `ps`/process listings.
curl -X POST https://asu-plugin-api.vercel.app/api/search-images \
  -H @- \
  -H "Content-Type: application/json" \
  -d '{
    "query": "[descriptive search terms]",
    "license": "cc0,by,by-sa",
    "per_page": 6
  }' <<HEADERS
Authorization: Bearer $CANVAS_TOKEN
X-Canvas-Domain: $CANVAS_DOMAIN
HEADERS
```

**Search strategy**:
1. Start with specific academic terms: `"cellular respiration diagram labeled"`
2. If few results, broaden: `"cellular respiration biology"`
3. Try multiple queries for the same concept (synonyms, different angles)
4. For scientific/medical: add `"educational"` or `"textbook"` to queries
5. For historical: add dates or era names

**License defaults**: Always use `"cc0,by,by-sa"` (Tier 1 + Tier 2). Only expand to `"cc0,by,by-sa,by-nc,by-nc-sa"` if the first search yields fewer than 3 results and the user approves.

**If search yields poor results** (fewer than 2 relevant images after 2-3 query attempts):
- Do NOT silently switch to AI generation
- Tell the user: *"I searched for [concept] using several terms but couldn't find a high-quality, properly-licensed image. Here are your options:"*
- Present an `AskUserQuestion`:

| Label | Description |
|---|---|
| **Generate with AI** | Create a custom image (I'll flag it for accuracy review if it's technical content) |
| **Try different terms** | Let me suggest different search keywords |
| **Skip this image** | No image needed here — move on |

If the user picks **Generate with AI**, switch to Mode 2 Step 3-G with the same context.

### Step 4-S: Present Candidates

For each image need, present the top 3-4 candidates. For each candidate, show:

1. **Thumbnail** — Save the image to a temporary local file and display using the Read tool so the user can see it inline
2. **Title and source**
3. **License** (CC0, CC-BY, etc.)
4. **Dimensions** (flag if under 800px wide)
5. **Attribution line** (pre-built from API response)
6. **Relevance note** — Brief explanation of why this image fits the learning objective

Present an `AskUserQuestion` per image need:

**Question**: "Which image works best for [context]?"

| Label | Description |
|---|---|
| **Option A** | [Image title] — [source] |
| **Option B** | [Image title] — [source] |
| **Option C** | [Image title] — [source] |
| **Search again** | Try different search terms |
| **Generate instead** | Create a custom image with AI |
| **Skip** | No image needed here |

- **Option A/B/C**: Proceed to Step 5-S with the selected image.
- **Search again**: Ask for refined terms, re-run Step 3-S.
- **Generate instead**: Switch to Mode 2 Step 3-G with the context.
- **Skip**: Move to the next image need.

### Step 5-S: Review & Approve

Run through the review checklist from `standards/image-generation-guidelines.md`. Present the review card:

```
Image Review Card
---------------------
Title:        [Image title]
Source:       [Origin] via OpenVerse
License:      [CC-BY 2.0] — [license URL]
Attribution:  [Pre-built attribution string]
Dimensions:   [width x height]

Placement:    Module [N] > [Page name] > [Section]
Purpose:      [Instructional / Contextual]
Objective:    [Linked learning objective ID]

Alt text:     "[Draft alt text]"
Caption:      "Figure [N]: [Draft caption]"

  Relevance:     Directly supports [objective]
  Accuracy:      [Assessment — or flag for SME review]
  Accessibility: [Contrast OK / Text-free / Clear at small sizes]
  Resolution:    [width]px wide — [meets / below] 800px minimum
```

Ask the user to confirm or edit the alt text and caption. If the image is below 800px wide, warn that it may appear blurry in full-width layout and suggest using the Image + Concept Card (Component 14) instead.

After approval, proceed to the shared Upload, Embed, and Track steps below.

---

## Mode 2: Generate

Generate custom images using AI for Canvas course pages. Creates visuals that don't exist as stock or CC-licensed images — conceptual diagrams, process flows, abstract illustrations, branded graphics.

### Search-First Check

**Before generating any image, consider whether a real image would be better.**

If the image need involves scientific content, biological structures, medical illustrations, historical references, or real-world examples:
1. Tell the user: *"This looks like something where a real image would be more accurate. Let me search for one first."*
2. Attempt a search via Mode 1 Step 3-S
3. **If a good match is found**: use it instead of generating
4. **If no good match**: come back and offer to generate: *"I couldn't find a good vetted image for [concept]. Would you like me to generate one with AI? I'll flag it for accuracy review."*

**Skip this check** (generate directly) when:
- The user explicitly says "generate" or "create"
- The concept is abstract, custom, or course-specific with no real-world equivalent
- It's a process flow, decision tree, or branded graphic

### Model Selection Guide

| Model | Best For | Use When |
|---|---|---|
| **Nano Banana** (default) | All generation — especially images with text, labels, or annotations | Default for everything. Best text reproduction quality. |
| **Imagen 4 Fast** | Quick batch drafts (2-4 options), text-free visuals | Need multiple options to choose from, no text in image |
| **Imagen 4 Standard** | Final quality, text-free illustrations | Approved concept ready for course, no text needed |
| **Imagen 4 Ultra** | Maximum detail, complex text-free scenes | High-stakes hero images |

**Default workflow**: Nano Banana for initial generation, user reviews, refine conversationally with Nano Banana, finalize.
**Use Imagen 4 only when**: The image is purely visual with zero text/labels AND you want to generate multiple options at once (Imagen supports `count: 2-4`, Nano Banana generates one at a time).

### Step 1-G: Determine Scope

Present an `AskUserQuestion`:

**Question**: "What kind of image do you need?"

| Label | Description |
|---|---|
| **Describe what I need** | I'll tell you what to create |
| **Images for a module** | Generate visuals for a specific module's pages |
| **Suggest what I need** | Analyze my module and recommend what to generate |

- **Describe what I need**: Take the user's description and proceed to Step 3-G.
- **Images for a module**: Ask which module, read context from `course-config.json`, proceed to Step 2-G.
- **Suggest what I need**: Analyze the module (Step 2-G) and present recommendations before generating.

### Step 2-G: Analyze Module Context

Read `course-config.json` for the target module. Identify opportunities where AI-generated images add instructional value:

| Opportunity Type | When to Suggest | Style |
|---|---|---|
| **Process diagram** | Objective involves sequences, cycles, or stages | Clean diagram, isometric |
| **Concept illustration** | Abstract concept needs visual anchor | Conceptual illustration |
| **Comparison visual** | Objective involves contrasting two things | Side-by-side, clean diagram |
| **System overview** | Multiple components interact | Isometric, infographic |
| **Workflow/decision tree** | Procedural or decision-based content | Clean diagram |

**Never suggest AI generation for** (redirect to Mode 1):
- Medical/anatomical illustrations
- Historical photographs
- Data visualizations (charts, graphs)
- Maps presented as factual
- Images of real people

Present recommendations:
```
Based on Module [N]: [Title], I'd suggest generating:

1. [Description] — for the Lesson page, supporting objective [M.N]
   Style: [clean diagram / conceptual illustration / etc.]

2. [Description] — for the Overview page
   Style: [infographic / isometric / etc.]

Want to proceed with these, or adjust?
```

### Step 3-G: Build the Prompt

Using the guidelines from `standards/image-generation-guidelines.md`, construct a structured prompt.

**Audience default (always apply): every ASU course is college-level on ASU Online.** When the image depicts people, show adult college learners (18+ and older, including working adults), diverse across race, age, gender, and ability, in a realistic online-study setting. Children, K-12 classrooms, and juvenile aesthetics are a mismatch: do NOT generate them unless the course topic explicitly requires it (e.g. early-childhood education, pediatrics). If a scenario says "a student," default to an online college student / adult learner. See `standards/image-generation-guidelines.md` Audience & Representation.

```
[STYLE]: Clean, professional [style keyword] for a college-level [discipline] course.
[SUBJECT]: [Detailed description — be specific about elements, relationships, layout]
[CONTEXT]: Educational [image type] illustrating [learning objective reference].
[COMPOSITION]: [Aspect ratio], [framing], [visual hierarchy notes]
[CONSTRAINTS]: No text overlay. No watermarks. No photorealistic human faces
  (carve-out: adult-learner photos may be photorealistic).
  White or light neutral background. High contrast for accessibility.
  Only include elements necessary to convey the concept.
[PEOPLE]: If people appear: adult college learners, diverse, online-study
  setting. No children or K-12 settings unless the course topic requires it.
[COLOR]: Clear, distinct colors. Avoid red-green only differentiation.
```

**Show the prompt to the user** before generating:
"Here's the prompt I'll use — want to adjust anything?"

### Step 4-G: Generate Draft Images

Call the proxy endpoint using **Nano Banana by default**:

```bash
# Auth headers piped via stdin (not argv) so CANVAS_TOKEN never appears in `ps`/process listings.
curl -X POST https://asu-plugin-api.vercel.app/api/generate-image-google \
  -H @- \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "[constructed prompt]",
    "model": "nano-banana",
    "aspect": "16:9"
  }' <<HEADERS
Authorization: Bearer $CANVAS_TOKEN
X-Canvas-Domain: $CANVAS_DOMAIN
HEADERS
```

**Note**: Nano Banana generates one image per request (conversational model). If the user wants multiple options to compare, use `"model": "imagen-4-fast"` with `"count": 2` — but only for text-free images.

The response contains base64-encoded images. For each image:

1. Decode and save to a temporary local file named `gen-[module]-[timestamp]-[N].png`
2. Display to the user using the Read tool (inline preview in Claude Code)
3. Label each option (A, B, etc.)

### Step 5-G: User Review

Present an `AskUserQuestion`:

**Question**: "Here are the drafts. Which direction works best?"

| Label | Description |
|---|---|
| **Option A** | Use this one |
| **Option B** | Use this one |
| **Refine Option [X]** | I like this one but it needs changes |
| **Regenerate** | Try again with a different approach |
| **Switch to search** | I'd rather find a real image for this |

- **Option A/B**: Proceed to Step 7-G (generate final quality version).
- **Refine**: Switch to iterative refinement (Step 6-G).
- **Regenerate**: Adjust the prompt and re-run Step 4-G.
- **Switch to search**: Hand off to Mode 1 Step 3-S with the context.

### Step 6-G: Iterative Refinement (Nano Banana)

When the user wants to refine a specific image, use Nano Banana for conversational editing:

```bash
# Auth headers piped via stdin (not argv) so CANVAS_TOKEN never appears in `ps`/process listings.
curl -X POST https://asu-plugin-api.vercel.app/api/generate-image-google \
  -H @- \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Take this educational diagram and [user requested change]. Keep the same clean, professional style.",
    "model": "nano-banana"
  }' <<HEADERS
Authorization: Bearer $CANVAS_TOKEN
X-Canvas-Domain: $CANVAS_DOMAIN
HEADERS
```

Continue the conversation naturally:
- "Make the arrows larger and add color coding"
- "Change the background to white"
- "Simplify — too many elements"
- "Add a third stage to the process"

Each iteration: save, display inline, ask if they want to continue refining or finalize.

### Step 7-G: Generate Final Version

Once the user approves a direction, generate the final version at higher quality:

```bash
# Auth headers piped via stdin (not argv) so CANVAS_TOKEN never appears in `ps`/process listings.
curl -X POST https://asu-plugin-api.vercel.app/api/generate-image-google \
  -H @- \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "[refined prompt]",
    "model": "imagen-4-standard",
    "aspect": "[chosen aspect]",
    "count": 1
  }' <<HEADERS
Authorization: Bearer $CANVAS_TOKEN
X-Canvas-Domain: $CANVAS_DOMAIN
HEADERS
```

Save the final image and display it for confirmation.

### Step 8-G: Review & Approve

Present the review card (adapted for generated images):

```
Image Review Card
---------------------
Model:        [Nano Banana / Imagen 4 Standard]
Prompt:       [The prompt used]
Generated:    [timestamp]

Placement:    Module [N] > [Page name] > [Section]
Purpose:      [Instructional / Contextual]
Objective:    [Linked learning objective ID]

Alt text:     "[Draft alt text] (AI-generated illustration)"
Caption:      "Figure [N]: [Draft caption]"
AI disclosure: "AI-generated illustration using [model name]"

  Relevance:     Directly supports [objective]
  Accuracy:      [Visual inspection — flag scientific content for SME review]
  Accessibility: Contrast OK, text-free, clear at small sizes
  Resolution:    Generated at [dimensions]
```

**Accuracy check**: If the image depicts scientific processes, anatomical structures, or discipline-specific content, flag it:
"This image shows [scientific content]. I'd recommend having a subject-matter expert verify accuracy before publishing. Want to proceed anyway, or flag it for review?"

After approval, proceed to the shared Upload, Embed, and Track steps below.

---

## Mode 3: Course-Wide Scan

Analyze all modules and plan images across the entire course, classifying each opportunity as search-first or generate.

### Step 1-CW: Analyze All Modules

Read all modules from `course-config.json`. For each module, identify 2-3 pages that would benefit most from images (typically Lesson and Overview pages). For each image opportunity, classify it:

| Classification | Criteria | Action |
|---|---|---|
| **Search-first** | Real-world subject, factual content, scientific/medical/historical | Search (Mode 1), fall back to generate if nothing found |
| **Generate** | Abstract concept, custom diagram, process flow, branded visual | Generate directly (Mode 2) |

### Step 2-CW: Present Plan

Present the full plan for user approval:

```
Image Plan for [Course Name]
-----------------------------

Module 1: [Title]
  1. [Description] — Lesson page — SEARCH (real-world example of [topic])
  2. [Description] — Overview page — GENERATE (process diagram for [concept])

Module 2: [Title]
  3. [Description] — Lesson page — SEARCH (historical photograph of [subject])
  4. [Description] — Lesson page — GENERATE (concept comparison: [A] vs [B])

...

Total: [N] images across [M] modules
  [X] to search, [Y] to generate

Want to proceed with this plan, or adjust anything?
```

### Step 3-CW: Execute Module by Module

After approval, process each module sequentially:

1. For **search-first** items: Run Mode 1 Steps 3-S through 5-S. If search fails, offer to generate.
2. For **generate** items: Run Mode 2 Steps 3-G through 8-G.
3. After each image, run the shared Upload, Embed, and Track steps.
4. Between modules, give a brief progress update.

### Step 4-CW: Summary

At the end, present a summary:

```
Image Summary
----------------
Total images added: [N]
  Searched: [X] images from CC-licensed sources
  Generated: [Y] AI-created images
Modules covered: [list]
License breakdown: [N] CC0, [N] CC-BY, [N] CC-BY-SA
AI-generated: [Y] images (all flagged with AI disclosure)
SME review needed: [Z] images flagged for accuracy review
All images tracked in course-config.json
```

---

## Shared Steps: Stage, Embed, Track

These steps apply to all modes after an image has been approved.

### Stage the Image (Upload is Deferred to Push)

Page images follow the same stage-to-preview-to-push gate as all other content.
Do NOT upload to Canvas at this point.

1. **Download the image** to a temp file (if not already local):
   ```bash
   curl -o /tmp/m[N]-img-[NNN].[ext] "[image URL]"
   ```

2. **Stage the image bytes** via `staging_manager --type files`:
   ```bash
   python3 scripts/staging_manager.py \
     --course-id [courseId] \
     --type files \
     --file /tmp/m[N]-img-[NNN].[ext] \
     --key m[N]-img-[NNN] \
     --alt "[alt text]" \
     --attribution "[attribution string or AI disclosure]" \
     --source-url "[original URL if searched]" \
     --module [N]
   ```
   The command returns `{"ok": true, ..., "url_token": "asucb-staged-file://m[N]-img-[NNN]"}`.

3. **Capture the url_token** (`asucb-staged-file://{key}`) returned by the staging command.
   This token is used as the `<img src>` in the page HTML for both local preview and
   push-time resolution.

Upload to Canvas Files happens automatically at push time: `push_to_canvas.py` scans the page
body for `asucb-staged-file://{key}` tokens, uploads each staged file, rewrites the src to
the Canvas embed URL (`/courses/{id}/files/{file_id}/preview`), then pushes the page atomically.
Staging is cleared only on overall success.

### Embed in Page — Layout-Aware Placement

Choose the component based on the page context, not just the image. Read the **Image Placement & Layout Guidelines** in `standards/image-generation-guidelines.md`.

**Before placing the image**, scan the current page HTML to understand the existing layout:
- How many images are already on this page?
- What layouts are already used (full-width vs. side-by-side)?
- Where does this image fall in the reading flow?

| Context | Component | Layout |
|---|---|---|
| Image is the focal point of a section | **Component 13**: Full-width Instructional Image | Image above, caption below |
| Image supports a concept being explained nearby | **Component 14**: Image + Concept Card | Image left, text right (side-by-side) |
| Comparing two states, conditions, or approaches | **Component 15**: Image Comparison | Two images side-by-side |
| Module overview or section opener | **Component 13** at 16:9 | Hero-style banner image at top of page |

**Vary your layouts.** If the page already has a full-width image, use an Image + Concept Card for the next one. Don't stack 3 full-width images in a row — it looks monotonous and overwhelms the learner. Aim for visual rhythm.

**Limit images per page.** 1-3 images per page is ideal. More than 4 creates cognitive overload.

Generate the HTML using the `asucb-staged-file://{key}` token as the `<img src>`, with alt text,
caption, and attribution. For AI-generated images, always include AI disclosure in the attribution line.

Example image tag (local preview and push-time token):
```html
<img src="asucb-staged-file://m1-img-001"
     alt="[alt text]"
     style="max-width: 100%; height: auto;" />
```

Then:

1. Show the HTML to the user. Ask: "Ready to stage this for **[Page Name]** on **[Course Name]**?"

After confirmation, fetch the current page HTML, insert the image component at the appropriate
location, and stage the updated page via `staging_manager.py`. The staging preview will render
the image by serving the staged bytes from the local staging server. Push when ready via
`push_to_canvas.py` (use the standard push flow: preview at `http://127.0.0.1:8111/...`, then
explicit push verb).

### Track in Config

Save the image metadata to `course-config.json` under `modules[N].images[]`.
`canvas_file_id` is not yet known at stage time; update it after push if needed
(push_to_canvas.py returns the file id in the result).

**For searched images:**

```json
{
  "id": "M1-img-001",
  "filename": "m1-img-001.jpg",
  "staged_key": "m1-img-001",
  "page_slug": "m1-lesson-topic",
  "placement": "After Concept 2",
  "purpose": "instructional",
  "alt_text": "...",
  "caption": "Figure 1: ...",
  "source": {
    "type": "searched",
    "origin": "flickr via OpenVerse",
    "url": "https://live.staticflickr.com/...",
    "author": "Author Name",
    "license": "CC-BY 2.0",
    "attribution": "\"Title\" by Author is licensed under CC BY 2.0..."
  },
  "review": {
    "relevance": "Supports M1.2: Explain the mechanism...",
    "accuracy_verified": true,
    "sme_review_needed": false,
    "accessibility_checked": true,
    "approved_by": "user",
    "approved_at": "2026-03-20T14:00:00Z"
  }
}
```

**For generated images:**

```json
{
  "id": "M1-img-002",
  "filename": "m1-img-002.png",
  "staged_key": "m1-img-002",
  "page_slug": "m1-lesson-topic",
  "placement": "After introduction",
  "purpose": "instructional",
  "alt_text": "Diagram showing the three stages of... (AI-generated illustration)",
  "caption": "Figure 2: The three stages of...",
  "source": {
    "type": "generated",
    "model": "imagen-4-standard",
    "prompt": "Clean, professional educational diagram...",
    "generated_at": "2026-03-20T14:45:00Z",
    "ai_disclosure": "AI-generated illustration using Google Imagen 4"
  },
  "review": {
    "relevance": "Supports M1.3: Analyze the relationship...",
    "accuracy_verified": false,
    "sme_review_needed": true,
    "accessibility_checked": true,
    "approved_by": "user",
    "approved_at": "2026-03-20T14:50:00Z"
  }
}
```

---

## Continue or Done

After any image is placed, present an `AskUserQuestion`:

**Question**: "Image added. What's next?"

| Label | Description |
|---|---|
| **Find more images** | Search for another image (Mode 1) |
| **Generate an image** | Create a custom image with AI (Mode 2) |
| **Course-wide scan** | Plan images across all modules (Mode 3) |
| **Done** | Finished adding images |

---

## Prompt Library (Quick-Start Templates for Generation)

These are starting templates for Mode 2 — always customize with module-specific content.

### Process/Cycle Diagram
```
Clean educational diagram showing [process name] with [N] clearly labeled stages
arranged in a [linear/circular] flow. Each stage shown as a distinct rounded
rectangle with a short label. Arrows connect stages showing direction of flow.
White background, professional flat design, high contrast colors.
For a college-level [discipline] course.
```

### Concept Comparison
```
Professional side-by-side comparison illustration showing [concept A] on the left
and [concept B] on the right. Each side uses distinct color coding. Key differences
highlighted with visual contrast. Clean minimal style, white background,
educational infographic quality. No text overlay.
```

### System Overview (Isometric)
```
Clean isometric illustration showing [system name] with [N] main components.
Components labeled with simple icons. Connections shown with clear lines/arrows.
Professional technical illustration style. Light neutral background.
Suitable for a college-level [discipline] course introduction.
```

### Abstract Concept
```
Minimalist conceptual illustration representing [concept]. Symbolic visual
metaphor using [suggested visual elements]. Professional, modern design.
Warm neutral palette with [primary accent color] highlights.
Educational context, not decorative. White background.
```

### Workflow/Decision Tree
```
Clean flowchart showing [process name] with [N] decision points. Diamond shapes
for decisions, rectangles for actions, arrows for flow direction. Two possible
outcomes shown in distinct colors. Professional diagram style, white background.
Suitable for [discipline] course.
```

---

## Output

The skill produces:
1. Properly-licensed or AI-generated images staged locally in `courses/{id}/staging/files/`
   (bytes + sidecar). Canvas Files upload is deferred to push time.
2. Page HTML staged with `asucb-staged-file://{key}` tokens as the `<img src>`.
   The staging server serves the bytes locally so the preview renders without Canvas.
3. At push time, `push_to_canvas.py` resolves tokens: uploads each staged image to
   Canvas Files (`images/m{N}/`), rewrites src to `/courses/{id}/files/{file_id}/preview`,
   and clears staged files only on full success.
4. Image metadata tracked in `course-config.json` with full provenance (search source or prompt history)
5. Attribution preserved in figure captions; AI disclosure included for generated images
6. SME review flags for scientific/technical AI-generated content
