Skip to content

Commit 5a5c7a7

Browse files
ouiliameclaude
andcommitted
academy: self-hosted video player, sectioned IA, lesson videos + related docs
- VideoPlaceholder plays self-hosted MP4 (Vercel Blob via getAssetUrl) instead of YouTube; resolves absolute URLs, /static paths, and bare asset names - Restructure foundations into sections: Get Started, Workflows (intro, branching, loops, subworkflows), Agents, Tables, Files, Knowledge Bases — each topic a folder with an intro page; eyebrows match their section - Wire all uploaded lesson videos; scaffold the three Workflows sub-lessons - Add a "Related documentation" section to every lesson linking the reference docs; fix in-body cross-links broken by the folder move Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 9623063 commit 5a5c7a7

15 files changed

Lines changed: 186 additions & 42 deletions

File tree

apps/docs/components/ui/video-placeholder.tsx

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client'
22

33
import { useState } from 'react'
4-
import { cn } from '@/lib/utils'
4+
import { cn, getAssetUrl } from '@/lib/utils'
55

66
interface VideoPlaceholderProps {
77
/** Large title shown on the hero. */
@@ -10,17 +10,19 @@ interface VideoPlaceholderProps {
1010
eyebrow?: string
1111
/** Pill in the top-right corner. Defaults to "Coming soon" (shown only until a video is set). */
1212
label?: string
13-
/** YouTube video id or URL. When set, the play button loads the video; otherwise the card is "coming soon". */
14-
youtube?: string
13+
/**
14+
* Self-hosted video source. Accepts an absolute URL, a root-relative path
15+
* (`/static/...`), or a bare asset name resolved through the Blob CDN. When
16+
* set, the play button loads the video; otherwise the card is "coming soon".
17+
*/
18+
src?: string
1519
className?: string
1620
}
1721

18-
/** Pull an 11-char YouTube id out of an id or any common YouTube URL. */
19-
function parseYouTubeId(input?: string): string | null {
20-
if (!input) return null
21-
if (/^[\w-]{11}$/.test(input)) return input
22-
const match = input.match(/(?:youtu\.be\/|[?&]v=|\/embed\/|\/shorts\/)([\w-]{11})/)
23-
return match ? match[1] : null
22+
/** Resolve a video source: pass absolute/root-relative through, send bare names to the Blob CDN. */
23+
function resolveVideoSrc(src: string): string {
24+
if (/^https?:\/\//.test(src) || src.startsWith('/')) return src
25+
return getAssetUrl(src)
2426
}
2527

2628
/** The sim logotype, drawn with currentColor so the theme can tint it. */
@@ -37,33 +39,35 @@ function SimWordmark({ className }: { className?: string }) {
3739

3840
/**
3941
* A 16:9 lesson hero used across the Academy. Always shows the design-system
40-
* video card (title, blueprint grid, theme-aware dark/light). When a `youtube`
41-
* id/URL is provided the play button loads the video inline; otherwise the card
42-
* reads "Coming soon" and the play button is muted.
42+
* video card (title, blueprint grid, theme-aware dark/light). When a `src` is
43+
* provided the play button loads the self-hosted video inline; otherwise the
44+
* card reads "Coming soon" and the play button is muted.
4345
*/
4446
export function VideoPlaceholder({
4547
title,
4648
eyebrow,
4749
label = 'Coming soon',
48-
youtube,
50+
src,
4951
className,
5052
}: VideoPlaceholderProps) {
51-
const videoId = parseYouTubeId(youtube)
53+
const hasVideo = Boolean(src)
5254
const [playing, setPlaying] = useState(false)
5355

54-
if (playing && videoId) {
56+
if (playing && src) {
5557
return (
5658
<div
5759
className={cn(
5860
'not-prose my-6 aspect-video w-full overflow-hidden rounded-[20px] bg-black',
5961
className
6062
)}
6163
>
62-
<iframe
63-
src={`https://www.youtube-nocookie.com/embed/${videoId}?autoplay=1&rel=0`}
64+
{/* biome-ignore lint/a11y/useMediaCaption: lesson videos have no caption track yet */}
65+
<video
66+
src={resolveVideoSrc(src)}
6467
title={title ?? 'Lesson video'}
65-
allow='autoplay; encrypted-media; picture-in-picture; fullscreen'
66-
allowFullScreen
68+
controls
69+
autoPlay
70+
playsInline
6771
className='h-full w-full border-0'
6872
/>
6973
</div>
@@ -100,7 +104,7 @@ export function VideoPlaceholder({
100104
))}
101105

102106
{/* Top-right status pill — only until a video is wired up */}
103-
{!videoId && (
107+
{!hasVideo && (
104108
<span className='absolute top-6 right-6 z-10 inline-flex items-center gap-2 rounded-full border border-[#E6E6E6] bg-white px-4 py-2 font-medium text-[12px] text-[#5F5F5F] uppercase tracking-[0.14em] md:top-8 md:right-8 dark:border-white/12 dark:bg-[#1A1A1A] dark:text-[#E6E6E6]'>
105109
<span className='size-1.5 rounded-full bg-[#1F8A5B]' />
106110
{label}
@@ -128,7 +132,7 @@ export function VideoPlaceholder({
128132

129133
{/* Centered play button — active when a video is wired, muted otherwise */}
130134
<div className='absolute inset-0 z-10 grid place-items-center'>
131-
{videoId ? (
135+
{hasVideo ? (
132136
<button
133137
type='button'
134138
onClick={() => setPlaying(true)}

apps/docs/content/docs/en/academy/agents.mdx renamed to apps/docs/content/docs/en/academy/agents/intro.mdx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { VideoPlaceholder } from '@/components/ui/video-placeholder'
77
import { WhatYouWillLearn } from '@/components/ui/what-you-will-learn'
88
import { VideoChapters } from '@/components/ui/video-chapters'
99

10-
<VideoPlaceholder eyebrow="Foundations" title="Agents" className="mt-2" />
10+
<VideoPlaceholder eyebrow="Agents" title="Agents" src="https://nnjgp7vypgx4myuq.public.blob.vercel-storage.com/academy-preview/agents-intro-light-with-intro.mp4" className="mt-2" />
1111

1212
<div className="mt-8 grid grid-cols-1 items-start gap-10 lg:grid-cols-[1fr_300px]">
1313
<div>
@@ -47,7 +47,7 @@ In Sim, you build AI agents as **workflows that use the Agent block**. There's n
4747

4848
## An agent is a workflow
4949

50-
This is the one idea to hold onto: **an AI agent is a workflow** — one built around the Agent block. Everything you learned about [workflows](/academy/workflows) applies. You don't leave the model; you add reasoning to it.
50+
This is the one idea to hold onto: **an AI agent is a workflow** — one built around the Agent block. Everything you learned about [workflows](/academy/workflows/intro) applies. You don't leave the model; you add reasoning to it.
5151

5252
## Inside the Agent block
5353

@@ -71,3 +71,11 @@ The clearest way to see an agent isn't to build one from nothing — it's to tak
7171
Your ability to compose workflows that make **multiple agent calls** is central to designing intelligent processes. And every agentic workflow you build becomes a building block — your workspace's library of agents composes into larger AI systems.
7272

7373
Start with one Agent block; the platform scales as your ambition does. The most sophisticated systems are just more of these, composed — more agent blocks swapping in, more reasoning, more reach, all from the same model you learned here.
74+
75+
## Related documentation
76+
77+
- [Agents overview](/agents)
78+
- [Choosing a model](/agents/choosing)
79+
- [Custom tools](/agents/custom-tools)
80+
- [MCP](/agents/mcp)
81+
- [Skills](/agents/skills)

apps/docs/content/docs/en/academy/files.mdx renamed to apps/docs/content/docs/en/academy/files/intro.mdx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { VideoPlaceholder } from '@/components/ui/video-placeholder'
77
import { WhatYouWillLearn } from '@/components/ui/what-you-will-learn'
88
import { VideoChapters } from '@/components/ui/video-chapters'
99

10-
<VideoPlaceholder eyebrow="Foundations" title="Files" className="mt-2" />
10+
<VideoPlaceholder eyebrow="Files" title="Files" src="https://nnjgp7vypgx4myuq.public.blob.vercel-storage.com/academy-preview/files-light-with-intro.mp4" className="mt-2" />
1111

1212
<div className="mt-8 grid grid-cols-1 items-start gap-10 lg:grid-cols-[1fr_300px]">
1313
<div>
@@ -58,3 +58,9 @@ The point isn't a new concept to learn — it's recognizing that the file-based
5858
- Produce a rendered document, chart, or audio file as a workflow's output.
5959

6060
If you're thinking "could I automate the thing that involves *that* document?" — the answer is almost always yes. Files are how Sim handles the real assets your processes already run on.
61+
62+
## Related documentation
63+
64+
- [Files overview](/files)
65+
- [Using files in workflows](/files/using-in-workflows)
66+
- [Generating files](/files/generating)

apps/docs/content/docs/en/academy/index.mdx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ description: Sim is a unified workspace for building and operating AI systems
66
import { VideoPlaceholder } from '@/components/ui/video-placeholder'
77
import { WhatYouWillLearn } from '@/components/ui/what-you-will-learn'
88

9-
<VideoPlaceholder eyebrow="Foundations" title="What is Sim?" className="mt-2" />
9+
<VideoPlaceholder eyebrow="Get Started" title="What is Sim?" src="https://nnjgp7vypgx4myuq.public.blob.vercel-storage.com/academy-preview/what-is-sim-light-with-intro.mp4" className="mt-2" />
1010

1111
Sim is a unified workspace for **building and operating AI systems**. Everything you make lives in one place, and everything connects.
1212

@@ -27,7 +27,7 @@ Sim is a unified workspace for **building and operating AI systems**. Everything
2727

2828
A **workspace** is a collection of shared resources and the workflows that use them.
2929

30-
- **Resources** are your data: [tables](/academy/tables) (structured records), [knowledge bases](/academy/knowledge-bases) (searchable memory), and [files](/academy/files) (documents and media).
30+
- **Resources** are your data: [tables](/academy/tables/intro) (structured records), [knowledge bases](/academy/knowledge-bases/intro) (searchable memory), and [files](/academy/files/intro) (documents and media).
3131
- **Workflows** are your processes — the agents and automations that read those resources, act, and write results back.
3232

3333
Everything in a workspace can see everything else in it. A workflow reads a table, searches a knowledge base, produces a file — and the next workflow picks up where it left off.
@@ -37,3 +37,8 @@ Everything in a workspace can see everything else in it. A workflow reads a tabl
3737
**Integrations** are plugins. They let your resources and workflows reach services beyond Sim — send a Slack message, read a Gmail inbox, write a row to a CRM, call any API. You connect an account once, and any workflow can use it.
3838

3939
So the whole picture is small: a workspace is **data + processes**, integrations plug it into **everything else**, and the rest of this course is just learning each piece and watching them compose.
40+
41+
## Related documentation
42+
43+
- [Introduction](/introduction)
44+
- [Getting started](/getting-started)

apps/docs/content/docs/en/academy/knowledge-bases.mdx renamed to apps/docs/content/docs/en/academy/knowledge-bases/intro.mdx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { VideoPlaceholder } from '@/components/ui/video-placeholder'
77
import { WhatYouWillLearn } from '@/components/ui/what-you-will-learn'
88
import { VideoChapters } from '@/components/ui/video-chapters'
99

10-
<VideoPlaceholder eyebrow="Foundations" title="Knowledge Bases" className="mt-2" />
10+
<VideoPlaceholder eyebrow="Knowledge Bases" title="Knowledge Bases" src="https://nnjgp7vypgx4myuq.public.blob.vercel-storage.com/academy-preview/knowledge-bases-light-with-intro.mp4" className="mt-2" />
1111

1212
<div className="mt-8 grid grid-cols-1 items-start gap-10 lg:grid-cols-[1fr_300px]">
1313
<div>
@@ -61,6 +61,12 @@ Use a Knowledge block with a query and it returns the most relevant chunks, each
6161

6262
## Grounding an answer
6363

64-
On its own, that's retrieval. The power comes one step later: feed those chunks into an [Agent](/academy/agents) block's context, and the model answers from your actual documents — accurate, up to date, and able to **cite** where each fact came from. That's grounding plus retrieval.
64+
On its own, that's retrieval. The power comes one step later: feed those chunks into an [Agent](/academy/agents/intro) block's context, and the model answers from your actual documents — accurate, up to date, and able to **cite** where each fact came from. That's grounding plus retrieval.
6565

6666
Knowledge bases power systems that need to give agents accurate, current context — and they're where you store what your systems learn over time.
67+
68+
## Related documentation
69+
70+
- [Knowledge Bases overview](/knowledgebase)
71+
- [Using a knowledge base in workflows](/knowledgebase/using-in-workflows)
72+
- [Connectors](/knowledgebase/connectors)

apps/docs/content/docs/en/academy/meta.json

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,19 @@
44
"pages": [
55
"---Get Started---",
66
"index",
7-
"---Foundations---",
8-
"workflows",
9-
"agents",
10-
"knowledge-bases",
11-
"tables",
12-
"files",
7+
"---Workflows---",
8+
"workflows/intro",
9+
"workflows/branching",
10+
"workflows/loops",
11+
"workflows/subworkflows",
12+
"---Agents---",
13+
"agents/intro",
14+
"---Tables---",
15+
"tables/intro",
16+
"---Files---",
17+
"files/intro",
18+
"---Knowledge Bases---",
19+
"knowledge-bases/intro",
1320
"---Use Cases---",
1421
"use-cases/slack-it-triage",
1522
"use-cases/document-extraction",

apps/docs/content/docs/en/academy/tables.mdx renamed to apps/docs/content/docs/en/academy/tables/intro.mdx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { VideoPlaceholder } from '@/components/ui/video-placeholder'
77
import { WhatYouWillLearn } from '@/components/ui/what-you-will-learn'
88
import { VideoChapters } from '@/components/ui/video-chapters'
99

10-
<VideoPlaceholder eyebrow="Foundations" title="Tables" className="mt-2" />
10+
<VideoPlaceholder eyebrow="Tables" title="Tables" src="https://nnjgp7vypgx4myuq.public.blob.vercel-storage.com/academy-preview/tables-light-with-intro.mp4" className="mt-2" />
1111

1212
<div className="mt-8 grid grid-cols-1 items-start gap-10 lg:grid-cols-[1fr_300px]">
1313
<div>
@@ -63,3 +63,9 @@ Once you see a use case that way, building it in Sim is mostly wiring those oper
6363
Tables aren't only storage — they're a working surface for your AI systems. **Workflow columns** let you run an operation across every row at once, in parallel, so a table becomes the place you launch and track work in bulk.
6464

6565
That makes a table a powerful interface for automation — the place you manage and operate agentic processes at scale.
66+
67+
## Related documentation
68+
69+
- [Tables overview](/tables)
70+
- [Using tables in workflows](/tables/using-in-workflows)
71+
- [Workflow columns](/tables/workflow-columns)

apps/docs/content/docs/en/academy/use-cases/document-extraction.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,6 @@ Turn a pile of unstructured documents — invoices, contracts, forms — into st
3838

3939
## What you'll build
4040

41-
A **file** comes in, an **Agent** block extracts the fields into a [structured output](/academy/agents) so the shape is predictable, and a **Table** block writes the row. Run it across a batch and a folder of documents becomes a queryable table.
41+
A **file** comes in, an **Agent** block extracts the fields into a [structured output](/academy/agents/intro) so the shape is predictable, and a **Table** block writes the row. Run it across a batch and a folder of documents becomes a queryable table.
4242

43-
This composes [files](/academy/files), [agents](/academy/agents), and [tables](/academy/tables).
43+
This composes [files](/academy/files/intro), [agents](/academy/agents/intro), and [tables](/academy/tables/intro).

apps/docs/content/docs/en/academy/use-cases/monitoring-research.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,6 @@ Build a system that runs on a schedule, checks the sources you care about, resea
3838

3939
## What you'll build
4040

41-
A **Schedule trigger** kicks the workflow off. An **Agent** block with search tools gathers and reads sources, synthesizes what changed, and a final step delivers it — a Slack message, or a saved report [file](/academy/files).
41+
A **Schedule trigger** kicks the workflow off. An **Agent** block with search tools gathers and reads sources, synthesizes what changed, and a final step delivers it — a Slack message, or a saved report [file](/academy/files/intro).
4242

43-
This composes [workflows](/academy/workflows), [agents](/academy/agents), and [files](/academy/files).
43+
This composes [workflows](/academy/workflows/intro), [agents](/academy/agents/intro), and [files](/academy/files/intro).

apps/docs/content/docs/en/academy/use-cases/sales-data-enrichment.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,4 @@ Run your sales pipeline as data. Start with thin lead records in a table, enrich
4040

4141
Leads live in a **table**. A **workflow column** runs per row: it enriches the record, an **Agent** block scores the fit, and the results are written straight back into the table. The table becomes both the queue and the record.
4242

43-
This is [tables](/academy/tables) and [agents](/academy/agents) composed into a pipeline that operates at scale.
43+
This is [tables](/academy/tables/intro) and [agents](/academy/agents/intro) composed into a pipeline that operates at scale.

0 commit comments

Comments
 (0)