Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions .github/workflows/tutorials.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# The tutorial series: five episodes, each rendered in a light and a dark cut
# from one composition, plus the beat stills that back the slideshow on
# guide/tutorials.
#
# Nothing here enters the git tree. Cuts and stills are published to one
# reusable, unversioned release and staged into the site at build time, the same
# contract as the explainer.
name: tutorials

on:
pull_request:
paths:
- "media/tutorials/**"
- ".github/workflows/tutorials.yml"
push:
branches: [main]
paths:
- "media/tutorials/**"
- ".github/workflows/tutorials.yml"
workflow_dispatch:

concurrency:
group: tutorials-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

defaults:
run:
working-directory: media/tutorials

jobs:
check:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm
cache-dependency-path: media/tutorials/package-lock.json

# media/tutorials is a sibling of media/explainer, not nested inside it,
# so it cannot reach that toolchain by walking up. It carries its own,
# pinned to the same versions.
- run: npm ci

- name: Type-check the series
run: npm run typecheck

# A module-scope palette capture silently freezes the light colours and the
# dark cut renders half light, with no error anywhere.
- name: Check the palette is resolved at render time
run: node scripts/check-theme.mjs

publish:
if: github.event_name != 'pull_request'
needs: check
runs-on: ubuntu-latest
timeout-minutes: 180
permissions:
contents: write
actions: write # dispatch the docs deploy once the new cuts are up
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm
cache-dependency-path: media/tutorials/package-lock.json

- run: npm ci

- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('media/tutorials/package-lock.json') }}

- run: npx playwright install --with-deps chromium

- name: Render every episode, both palettes
run: node scripts/build-all.mjs

- name: Publish the cuts and the stills
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release view tutorials-latest >/dev/null 2>&1 || \
gh release create tutorials-latest --prerelease \
--title "Tutorials (latest)" \
--notes "Current cuts of the OO-LD tutorial series, light and dark, with the beat stills behind the slideshow. Rebuilt whenever media/tutorials changes; not versioned."
for ep in ep1 ep2 ep3 ep4 ep5; do
for theme in light dark; do
[ -f "$ep/out/$ep-$theme.mp4" ] && gh release upload tutorials-latest "$ep/out/$ep-$theme.mp4" --clobber
if [ -d "$ep/out/stills-$theme" ]; then
(cd "$ep/out/stills-$theme" && zip -qr "../../../$ep-$theme-stills.zip" .)
gh release upload tutorials-latest "$ep-$theme-stills.zip" --clobber
fi
done
done

# The docs deploy for this push staged whatever was on the release at the
# time, which is the previous set. Re-run it now the new one is up.
- name: Redeploy the docs with the new cuts
env:
GH_TOKEN: ${{ github.token }}
run: gh workflow run main.yml --ref main
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ __pycache__/
docs/meta/
docs/schemas/
docs/assets/video/
docs/assets/tutorials/

# IDE settings
.idea/
Expand Down
4 changes: 4 additions & 0 deletions .lycheeignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,7 @@ open-semantic-lab\.org/api/
/spec/meta/oold-ui-meta-schema\.json$
/spec/migration/from-legacy-osw/?$
/spec/use-cases/?$

# guide/tutorials links the served copy of an example; docs/schemas/ is staged
# into the site by `make stage-schemas` and is not in the tree at lint time.
^.*/docs/schemas/.*\.json$
10 changes: 7 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,20 @@ stage-schemas: ## Copy meta/ + examples/ into docs/ so the build serves them (ve
stage-video: ## Put the explainer cuts where the site can serve them (never committed)
@sh scripts/stage_video.sh

.PHONY: stage-tutorials
stage-tutorials: ## Put the tutorial cuts and beat stills where the site can serve them (never committed)
@sh scripts/stage_tutorials.sh

.PHONY: docs
docs: stage-schemas stage-video ## Serve the docs with live reload (serves the committed spec artifact)
docs: stage-schemas stage-video stage-tutorials ## Serve the docs with live reload (serves the committed spec artifact)
@$(ZENSICAL) serve

.PHONY: preview
preview: spec stage-schemas stage-video ## Regenerate the spec, then serve the docs with live reload
preview: spec stage-schemas stage-video stage-tutorials ## Regenerate the spec, then serve the docs with live reload
@$(ZENSICAL) serve

.PHONY: check
check: validate spec stage-schemas stage-video ## Validate schemas, lint the regenerated spec, and build the site
check: validate spec stage-schemas stage-video stage-tutorials ## Validate schemas, lint the regenerated spec, and build the site
@uv run scripts/check_spec.py
@uv run scripts/rules_baseline.py check
@$(MAKE) --no-print-directory check-extensions
Expand Down
3 changes: 3 additions & 0 deletions docs/guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

This guide is a non-normative walk-through of OO-LD Schema. It follows the same orientation as the [JSON-LD specification](https://www.w3.org/TR/json-ld/): each concept is introduced with a short explanation and worked examples. For the exact, normative rules - and the RFC 2119 keywords - always refer to the [Specification](../spec/).

If you would rather watch than read, the same ground is covered by five short [video tutorials](tutorials.md), each also available as a slideshow.

## OO-LD Concepts

- [Basic Concepts](basic-concepts.md) - how one document serves as both a JSON Schema and a JSON-LD context, and how inheritance is expressed.
Expand All @@ -13,6 +15,7 @@ This guide is a non-normative walk-through of OO-LD Schema. It follows the same

## Beyond the concepts

- [Video tutorials](tutorials.md) - the five-episode series, from why data needs meaning to the Python library, in light and dark, as video or slideshow.
- [Tooling](../tooling.md) - generic tooling, OO-LD-specific implementations, and interactive playgrounds.
- [Mappings](../mappings/index.md) - how selected formats (Asset Administration Shell, SAMM, LinkML, NOMAD, DLite, ...) map to OO-LD schemas and instances.
- [Migration](../migration/index.md) - reach OO-LD from where you already are: JSON Schema, RDF / JSON-LD, OWL or SHACL, a Python dataclass, or a legacy OSW schema.
Expand Down
88 changes: 88 additions & 0 deletions docs/guide/tutorials.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
title: Video tutorials
---

# Video tutorials

Five short episodes, each building on the one before, from first principles to the Python library. They are silent: the text on screen carries the script, so they work with the sound off.

Every episode is also a slideshow. Use **View as slideshow** to step through the same beats as stills, at your own pace, which is usually the better way to read the code.

<div class="tut" data-episode="ep1" markdown>
<div class="tut__head" markdown>
<h2 class="tut__title">1. Why data needs meaning</h2>
<button class="tut__toggle" type="button" aria-pressed="false">View as slideshow</button>
</div>

Why a schema on its own is not enough. A schema constrains the shape of your data and says nothing about what it means; a context supplies meaning and says nothing about shape.

<video class="tut__video" controls playsinline preload="metadata" aria-label="Episode 1: why data needs meaning"></video>
<div class="tut__gallery" tabindex="0">
<img class="tut__slide" alt="">
<div class="tut__controls"><button class="tut__prev" type="button" aria-label="Previous slide">&larr;</button><span class="tut__caption"></span><button class="tut__next" type="button" aria-label="Next slide">&rarr;</button></div>
</div>
</div>

<div class="tut" data-episode="ep2" markdown>
<div class="tut__head" markdown>
<h2 class="tut__title">2. Anatomy of an OO-LD document</h2>
<button class="tut__toggle" type="button" aria-pressed="false">View as slideshow</button>
</div>

A close reading of [`Minimal.schema.json`](../schemas/Minimal.schema.json), keyword by keyword: `$schema`, `$id`, `@context`, and the ordinary JSON Schema keywords beside them.

<video class="tut__video" controls playsinline preload="metadata" aria-label="Episode 2: anatomy of an OO-LD document"></video>
<div class="tut__gallery" tabindex="0">
<img class="tut__slide" alt="">
<div class="tut__controls"><button class="tut__prev" type="button" aria-label="Previous slide">&larr;</button><span class="tut__caption"></span><button class="tut__next" type="button" aria-label="Next slide">&rarr;</button></div>
</div>
</div>

<div class="tut" data-episode="ep3" markdown>
<div class="tut__head" markdown>
<h2 class="tut__title">3. Building objects from objects</h2>
<button class="tut__toggle" type="button" aria-pressed="false">View as slideshow</button>
</div>

Composition: `$ref` for reuse, `allOf` for extension, and what happens to the `@context` when schemas compose. See [Composition](composition.md) for the written version.

<video class="tut__video" controls playsinline preload="metadata" aria-label="Episode 3: building objects from objects"></video>
<div class="tut__gallery" tabindex="0">
<img class="tut__slide" alt="">
<div class="tut__controls"><button class="tut__prev" type="button" aria-label="Previous slide">&larr;</button><span class="tut__caption"></span><button class="tut__next" type="button" aria-label="Next slide">&rarr;</button></div>
</div>
</div>

<div class="tut" data-episode="ep4" markdown>
<div class="tut__head" markdown>
<h2 class="tut__title">4. Identity, instances and the graph</h2>
<button class="tut__toggle" type="button" aria-pressed="false">View as slideshow</button>
</div>

How instances get identity, how an instance plus its schema's context expands into triples, and how a set of documents becomes a graph. See [Schema Instances](schema-instances.md) and [Identification & Versioning](identification-versioning.md).

<video class="tut__video" controls playsinline preload="metadata" aria-label="Episode 4: identity, instances and the graph"></video>
<div class="tut__gallery" tabindex="0">
<img class="tut__slide" alt="">
<div class="tut__controls"><button class="tut__prev" type="button" aria-label="Previous slide">&larr;</button><span class="tut__caption"></span><button class="tut__next" type="button" aria-label="Next slide">&rarr;</button></div>
</div>
</div>

<div class="tut" data-episode="ep5" markdown>
<div class="tut__head" markdown>
<h2 class="tut__title">5. oold in Python</h2>
<button class="tut__toggle" type="button" aria-pressed="false">View as slideshow</button>
</div>

Putting it to work with the [`oold`](https://pypi.org/project/oold/) reference library: the graph-object binding, links, validation, and the DSL.

<video class="tut__video" controls playsinline preload="metadata" aria-label="Episode 5: oold in Python"></video>
<div class="tut__gallery" tabindex="0">
<img class="tut__slide" alt="">
<div class="tut__controls"><button class="tut__prev" type="button" aria-label="Previous slide">&larr;</button><span class="tut__caption"></span><button class="tut__next" type="button" aria-label="Next slide">&rarr;</button></div>
</div>
</div>

## Source

The episodes are authored in code, in `media/tutorials` in this repository, and rendered in a light and a dark cut from the same source. The stills behind the slideshow are the same frames the reviewers look at in every pull request.
15 changes: 14 additions & 1 deletion docs/javascripts/hero-video.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,25 @@
slate: 'assets/video/oold-explainer-dark.mp4',
};

// Asset URLs must be resolved against the site root, not the current page.
// This page lives at /guide/tutorials/ and the site is additionally served
// under a version prefix (/dev/, /1.0/), so neither a page-relative nor a
// root-absolute path works. The theme publishes the way back in its config.
function base() {
var el = document.getElementById('__config');
try {
var b = JSON.parse(el.textContent).base;
if (b) return b.replace(/\/+$/, '') + '/';
} catch (e) { /* fall through */ }
return '';
}

function apply() {
var video = document.querySelector('.oold-hero__video');
if (!video) return;

var scheme = document.body.getAttribute('data-md-color-scheme') || 'default';
var src = CUTS[scheme] || CUTS.default;
var src = base() + (CUTS[scheme] || CUTS.default);
if (video.getAttribute('src') === src) return;

video.setAttribute('src', src);
Expand Down
Loading
Loading