Repository: iiif-prezi/iiif-prezi3 (language: python)

Issue:
Fix serialization errors with `datetime` etc
Switch to using Pydantic's JSON encoder to handle types that cannot be serialized by the native `JSONEncoder` such as `datetime`

Fixes #150 
Fix skeleton modifier bug + add ManifestRef changes
Fixes a dumb bug with the skeleton modifier (not including the "before" text in the output when doing an insertion) and adds manifest reference changeset to allow extra properties.

Fixes #152 
Allow AutoLabel to work in other places that have a .label property
Such as `ExternalItem`, `ManifestRef` etc


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/recipes.yml b/.github/workflows/recipes.yml
new file mode 100644
index 0000000..57691eb
--- /dev/null
+++ b/.github/workflows/recipes.yml
@@ -0,0 +1,35 @@
+name: recipes
+
+on: [pull_request, workflow_dispatch]
+
+permissions:
+  contents: read
+
+jobs:
+  test-recipes:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v3
+      - name: Setup python
+        uses: actions/setup-python@v4
+        with:
+          python-version: 3.9
+          architecture: x64
+
+      - uses: actions/cache@v3
+        with:
+          path: |
+            ${{ env.pythonLocation }}
+            iiif-prezi3/iiif-prezi3/utils/.cache
+          key: ${{ env.pythonLocation }}-${{ hashFiles('setup.py') }}
+
+      - name: Install dev dependencies
+        run: |
+          python -m pip install --upgrade pip
+          pip install -e .
+          pip install -e .[dev]
+
+      - name: Run the Recipe Check script
+        run: |
+          cd utils
+          python test_cookbook.py -y -v --fail-fast --fail-missing ../docs/recipes/*.md
\ No newline at end of file
diff --git a/docs/recipes/0001-mvm-image.md b/docs/recipes/0001-mvm-image.md
index f9e9319..5a57a18 100644
--- a/docs/recipes/0001-mvm-image.md
+++ b/docs/recipes/0001-mvm-image.md
@@ -1,48 +1,16 @@
 # Simplest Manifest - Single Image File
-### Recipe: [https://iiif.io/api/cookbook/recipe/0001-mvm-image/](https://iiif.io/api/cookbook/recipe/0001-mvm-image/)
-### JSON-LD: [https://iiif.io/api/cookbook/recipe/0001-mvm-image/manifest.json](https://iiif.io/api/cookbook/recipe/0001-mvm-image/manifest.json)
+|              | **Cookbook URLs**                                                    | 
+|--------------|----------------------------------------------------------------------|
+| **Recipe:**  | [https://iiif.io/api/cookbook/recipe/0001-mvm-image/](https://iiif.io/api/cookbook/recipe/0001-mvm-image/)              |
+| **JSON-LD:** | [https://iiif.io/api/cookbook/recipe/0001-mvm-image/manifest.json](https://iiif.io/api/cookbook/recipe/0001-mvm-image/manifest.json) |
 
-## Method 1 - Using the `make_canvas` and `add_image` helpers
-```python
-from iiif_prezi3 import Manifest, config
-
-config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
 
-manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0001-mvm-image/manifest.json", label="Image 1")
-canvas = manifest.make_canvas(id="https://iiif.io/api/cookbook/recipe/0001-mvm-image/canvas/p1", height=1800, width=1200)
-anno_page = canvas.add_image(image_url="http://iiif.io/api/presentation/2.1/example/fixtures/resources/page1-full.png",
-                             anno_page_id="https://iiif.io/api/cookbook/recipe/0001-mvm-image/page/p1/1",
-                             anno_id="https://iiif.io/api/cookbook/recipe/0001-mvm-image/annotation/p0001-image",
-                             format="image/png",
-                             height=1800,
-                             width=1200
-                             )
-
-print(manifest.json(indent=2))
+### Method 1 - Using the `make_canvas` and `add_image` helpers
+```python
+--8<-- "docs/recipes/scripts/0001-mvm-image-method1.py"
 ```
 
-## Method 2 - Building the structure manually and using the `add_item` helper
+### Method 2 - Building the structure manually and using the `add_item` helper
 ```python
-from iiif_prezi3 import Manifest, Canvas, AnnotationPage, Annotation, ResourceItem, config
-
-config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
-
-manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0001-mvm-image/manifest.json", label="Image 1")
-canvas = Canvas(id="https://iiif.io/api/cookbook/recipe/0001-mvm-image/canvas/p1", height=1800, width=1200)
-anno_body = ResourceItem(id="http://iiif.io/api/presentation/2.1/example/fixtures/resources/page1-full.png",
-                    type="Image",
-                    format="image/png",
-                    height=1800,
-                    width=1200)
-anno_page = AnnotationPage(id="https://iiif.io/api/cookbook/recipe/0001-mvm-image/page/p1/1")
-anno = Annotation(id="https://iiif.io/api/cookbook/recipe/0001-mvm-image/annotation/p0001-image",
-                  motivation="painting",
-                  body=anno_body,
-                  target=canvas.id)
-anno_page.add_item(anno)
-canvas.add_item(anno_page)
-manifest.add_item(canvas)
-
-print(manifest.json(indent=2))
+--8<-- "docs/recipes/scripts/0001-mvm-image-method2.py"
 ```
-
diff --git a/docs/recipes/0002-mvm-audio.md b/docs/recipes/0002-mvm-audio.md
index 863af0b..74558bc 100644
--- a/docs/recipes/0002-mvm-audio.md
+++ b/docs/recipes/0002-mvm-audio.md
@@ -1,26 +1,10 @@
 # Simplest Manifest - Audio
-### Recipe: [https://iiif.io/api/cookbook/recipe/0002-mvm-audio/](https://iiif.io/api/cookbook/recipe/0002-mvm-audio/)
-### JSON-LD: [https://iiif.io/api/cookbook/recipe/0002-mvm-audio/manifest.json](https://iiif.io/api/cookbook/recipe/0002-mvm-audio/manifest.json)
+|              | **Cookbook URLs**                                                                                                                    |
+|--------------|--------------------------------------------------------------------------------------------------------------------------------------|
+| **Recipe:**  | [https://iiif.io/api/cookbook/recipe/0002-mvm-audio/](https://iiif.io/api/cookbook/recipe/0002-mvm-audio/)                           |
+| **JSON-LD:** | [https://iiif.io/api/cookbook/recipe/0002-mvm-audio/manifest.json](https://iiif.io/api/cookbook/recipe/0002-mvm-audio/manifest.json) |
 
-## Method 1 - Building the structure and using the `add_item` helper
+### Method 1 - Building the structure and using the `add_item` helper
 ```python
-from iiif_prezi3 import Manifest, AnnotationPage, Annotation, ResourceItem, config
-
-config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
-
-manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0002-mvm-audio/manifest.json", label="Simplest Audio Example")
-canvas = manifest.make_canvas(id="https://iiif.io/api/cookbook/recipe/0002-mvm-audio/canvas", duration=1985.024)
-anno_body = ResourceItem(id="https://fixtures.iiif.io/audio/indiana/mahler-symphony-3/CD1/medium/128Kbps.mp4",
-                    type="Sound",
-                    format="audio/mp4",
-                    duration=1985.024)
-anno_page = AnnotationPage(id="https://iiif.io/api/cookbook/recipe/0002-mvm-audio/canvas/page")
-anno = Annotation(id="https://iiif.io/api/cookbook/recipe/0002-mvm-audio/canvas/page/annotation",
-                  motivation="painting",
-                  body=anno_body,
-                  target=canvas.id)
-anno_page.add_item(anno)
-canvas.add_item(anno_page)
-
-print(manifest.json(indent=2))
+--8<-- "docs/recipes/scripts/0002-mvm-audio-method1.py"
 ```
diff --git a/docs/recipes/0003-mvm-video.md b/docs/recipes/0003-mvm-video.md
index 7cf2ec1..c885373 100644
--- a/docs/recipes/0003-mvm-video.md
+++ b/docs/recipes/0003-mvm-video.md
@@ -1,30 +1,10 @@
 # Simplest Manifest - Video
-### Recipe: [https://iiif.io/api/cookbook/recipe/0003-mvm-video/](https://iiif.io/api/cookbook/recipe/0003-mvm-video/)
-### JSON-LD: [https://iiif.io/api/cookbook/recipe/0003-mvm-video/manifest.json](https://iiif.io/api/cookbook/recipe/0003-mvm-video/manifest.json)
+|              | **Cookbook URLs**                                                                                                                    |
+|--------------|--------------------------------------------------------------------------------------------------------------------------------------|
+| **Recipe:**  | [https://iiif.io/api/cookbook/recipe/0003-mvm-video/](https://iiif.io/api/cookbook/recipe/0003-mvm-video/)                           |
+| **JSON-LD:** | [https://iiif.io/api/cookbook/recipe/0003-mvm-video/manifest.json](https://iiif.io/api/cookbook/recipe/0003-mvm-video/manifest.json) |
 
-## Method 1 - Building the structure manually and using the `add_item` helper
+### Method 1 - Building the structure manually and using the `add_item` helper
 ```python
-from iiif_prezi3 import Manifest, AnnotationPage, Annotation, ResourceItem, config
-
-config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
-
-manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0003-mvm-video/manifest.json", label="Video Example 3")
-canvas = manifest.make_canvas(id="https://iiif.io/api/cookbook/recipe/0003-mvm-video/canvas")
-anno_body = ResourceItem(id="https://fixtures.iiif.io/video/indiana/lunchroom_manners/high/lunchroom_manners_1024kb.mp4",
-                    type="Video",
-                    format="video/mp4")
-anno_page = AnnotationPage(id="https://iiif.io/api/cookbook/recipe/0003-mvm-video/canvas/page")
-anno = Annotation(id="https://iiif.io/api/cookbook/recipe/0003-mvm-video/canvas/page/annotation",
-                  motivation="painting",
-                  body=anno_body,
-                  target=canvas.id)
-
-hwd = {"height": 360, "width": 480, "duration": 572.034}
-anno_body.set_hwd(**hwd)
-canvas.set_hwd(**hwd)
-
-anno_page.add_item(anno)
-canvas.add_item(anno_page)
-
-print(manifest.json(indent=2))
+--8<-- "docs/recipes/scripts/0003-mvm-video-method1.py"
 ```
diff --git a/docs/recipes/0004-canvas-size.md b/docs/recipes/0004-canvas-size.md
index 5c82936..4d06ea3 100644
--- a/docs/recipes/0004-canvas-size.md
+++ b/docs/recipes/0004-canvas-size.md
@@ -1,29 +1,10 @@
 # Image and Canvas with Differing Dimensions
-### Recipe: [https://iiif.io/api/cookbook/recipe/0004-canvas-size/](https://iiif.io/api/cookbook/recipe/0004-canvas-size/)
-### JSON-LD: [https://iiif.io/api/cookbook/recipe/0004-canvas-size/manifest.json](https://iiif.io/api/cookbook/recipe/0004-canvas-size/manifest.json)
+|              | **Cookbook URLs**                                                                                                                        |
+|--------------|------------------------------------------------------------------------------------------------------------------------------------------|
+| **Recipe:**  | [https://iiif.io/api/cookbook/recipe/0004-canvas-size/](https://iiif.io/api/cookbook/recipe/0004-canvas-size/)                           |
+| **JSON-LD:** | [https://iiif.io/api/cookbook/recipe/0004-canvas-size/manifest.json](https://iiif.io/api/cookbook/recipe/0004-canvas-size/manifest.json) |
 
-## Method 1 - Using the `set_hwd` helper
+### Method 1 - Using the `set_hwd` helper
 ```python
-from iiif_prezi3 import Manifest, AnnotationPage, Annotation, ResourceItem, config
-
-config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
-
-manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0004-canvas-size/manifest.json", label="Still image from an opera performance at Indiana University")
-canvas = manifest.make_canvas(id="https://iiif.io/api/cookbook/recipe/0004-canvas-size/canvas/p1")
-anno_body = ResourceItem(id="https://fixtures.iiif.io/video/indiana/donizetti-elixir/act1-thumbnail.png",
-                    type="Image",
-                    format="image/png")
-anno_page = AnnotationPage(id="https://iiif.io/api/cookbook/recipe/0004-canvas-size/canvas/page/p1/1")
-anno = Annotation(id="https://iiif.io/api/cookbook/recipe/0004-canvas-size/annotation/p0001-image",
-                  motivation="painting",
-                  body=anno_body,
-                  target=canvas.id)
-
-anno_body.set_hwd(height=360, width=640)
-canvas.set_hwd(height=1080, width=1920)
-
-anno_page.add_item(anno)
-canvas.add_item(anno_page)
-
-print(manifest.json(indent=2))
+--8<-- "docs/recipes/scripts/0004-canvas-size-method1.py"
 ```
diff --git a/docs/recipes/0005-image-service.md b/docs/recipes/0005-image-service.md
index c8c5eef..17fac8b 100644
--- a/docs/recipes/0005-image-service.md
+++ b/docs/recipes/0005-image-service.md
@@ -1,20 +1,11 @@
 # Support Deep Viewing with Basic Use of a IIIF Image Service
-### Recipe: [https://iiif.io/api/cookbook/recipe/0005-image-service/](https://iiif.io/api/cookbook/recipe/0005-image-service/)
-### JSON-LD: [https://iiif.io/api/cookbook/recipe/0005-image-service/manifest.json](https://iiif.io/api/cookbook/recipe/0005-image-service/manifest.json)
+|              | **Cookbook URLs**                                                                                                                            |
+|--------------|----------------------------------------------------------------------------------------------------------------------------------------------|
+| **Recipe:**  | [https://iiif.io/api/cookbook/recipe/0005-image-service/](https://iiif.io/api/cookbook/recipe/0005-image-service/)                           |
+| **JSON-LD:** | [https://iiif.io/api/cookbook/recipe/0005-image-service/manifest.json](https://iiif.io/api/cookbook/recipe/0005-image-service/manifest.json) |
 
-## Method 1 - Using the `make_canvas_from_iiif` helper
+### Method 1 - Using the `make_canvas_from_iiif` helper
 ```python
-from iiif_prezi3 import Manifest, config
-
-config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
-
-manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0005-image-service/manifest.json", label="Picture of Göttingen taken during the 2019 IIIF Conference")
-canvas = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/918ecd18c2592080851777620de9bcb5-gottingen",
-                               id="https://iiif.io/api/cookbook/recipe/0005-image-service/canvas/p1",
-                               label="Canvas with a single IIIF image")
-canvas.items[0].id = "https://iiif.io/api/cookbook/recipe/0005-image-service/page/p1/1"
-canvas.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0005-image-service/annotation/p0001-image"
-
-print(manifest.json(indent=2))
+--8<-- "docs/recipes/scripts/0005-image-service-method1.py"
 ```
 
diff --git a/docs/recipes/0006-text-language.md b/docs/recipes/0006-text-language.md
index 902d5ef..53921e7 100644
--- a/docs/recipes/0006-text-language.md
+++ b/docs/recipes/0006-text-language.md
@@ -1,27 +1,10 @@
 # Internationalization and Multi-language Values
-### Recipe: [https://iiif.io/api/cookbook/recipe/0006-text-language/](https://iiif.io/api/cookbook/recipe/0006-text-language/)
-### JSON-LD: [https://iiif.io/api/cookbook/recipe/0006-text-language/manifest.json](https://iiif.io/api/cookbook/recipe/0006-text-language/manifest.json)
+|              | **Cookbook URLs**                                                                                                                            |
+|--------------|----------------------------------------------------------------------------------------------------------------------------------------------|
+| **Recipe:**  | [https://iiif.io/api/cookbook/recipe/0006-text-language/](https://iiif.io/api/cookbook/recipe/0006-text-language/)                           |
+| **JSON-LD:** | [https://iiif.io/api/cookbook/recipe/0006-text-language/manifest.json](https://iiif.io/api/cookbook/recipe/0006-text-language/manifest.json) |
 
-## Method 1 - Construct the language dictionaries during object creation
+### Method 1 - Construct the language dictionaries during object creation
 ```python
-from iiif_prezi3 import Manifest, KeyValueString
-
-manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0006-text-language/manifest.json",
-                    label={"en": ["Whistler's Mother"], "fr": ["La Mère de Whistler"]})
-manifest.metadata = [
-    KeyValueString(label={"en": ["Creator"], "fr": ["Auteur"]}, value="Whistler, James Abbott McNeill"),
-    KeyValueString(label={"en": ["Subject"], "fr": ["Sujet"]},
-                   value={"en": ["McNeill Anna Matilda, mother of Whistler (1804-1881)"],
-                          "fr": ["McNeill Anna Matilda, mère de Whistler (1804-1881)"]})
-]
-manifest.summary = {"en": ["Arrangement in Grey and Black No. 1, also called Portrait of the Artist's Mother."],
-                    "fr": ["Arrangement en gris et noir n°1, also called Portrait de la mère de l'artiste."]}
-manifest.requiredStatement = KeyValueString(label={"en": ["Held By"], "fr": ["Détenu par"]}, value="Musée d'Orsay, Paris, France")
-
-canvas = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/329817fc8a251a01c393f517d8a17d87-Whistlers_Mother",
-                                        id="https://iiif.io/api/cookbook/recipe/0006-text-language/canvas/p1")
-canvas.items[0].id = "https://iiif.io/api/cookbook/recipe/0006-text-language/page/p1/1"
-canvas.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0006-text-language/annotation/p0001-image"
-
-print(manifest.json(indent=2))
+--8<-- "docs/recipes/scripts/0006-text-language-method1.py"
 ```
diff --git a/docs/recipes/0007-string-formats.md b/docs/recipes/0007-string-formats.md
index c50cc13..7986ee7 100644
--- a/docs/recipes/0007-string-formats.md
+++ b/docs/recipes/0007-string-formats.md
@@ -1,24 +1,10 @@
 # Embedding HTML in descriptive properties
-### Recipe: [https://iiif.io/api/cookbook/recipe/0007-string-formats/](https://iiif.io/api/cookbook/recipe/0007-string-formats/)
-### JSON-LD: [https://iiif.io/api/cookbook/recipe/0007-string-formats/manifest.json](https://iiif.io/api/cookbook/recipe/0007-string-formats/manifest.json)
+|              | **Cookbook URLs**                                                                                                                             |
+|--------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
+| **Recipe:**  | [https://iiif.io/api/cookbook/recipe/0007-string-formats/](https://iiif.io/api/cookbook/recipe/0007-string-formats/)                          |
+| **JSON-LD:** | [https://iiif.io/api/cookbook/recipe/0007-string-formats/manifest.json](https://iiif.io/api/cookbook/recipe/0007-string-formats/manifest.json) |
 
-## Method 1 - Building the object directly and making use of the AutoLang config
+### Method 1 - Building the object directly and making use of the AutoLang config
 ```python
-from iiif_prezi3 import Manifest, KeyValueString, config
-
-config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
-
-manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0007-string-formats/manifest.json",
-                    label="Picture of Göttingen taken during the 2019 IIIF Conference",
-                    summary="<p>Picture taken by the <a href=\"https://github.com/glenrobson\">IIIF Technical Coordinator</a></p>",
-                    rights="http://creativecommons.org/licenses/by-sa/3.0/",
-                    requiredStatement=KeyValueString(label="Attribution",
-                                                     value="<span>Glen Robson, IIIF Technical Coordinator. <a href=\"https://creativecommons.org/licenses/by-sa/3.0\">CC BY-SA 3.0</a> <img src=\"https://licensebuttons.net/l/by-sa/3.0/88x31.png\"/></span>"),
-                    metadata=[KeyValueString(label="Author", value={"none": ["<span><a href='https://github.com/glenrobson'>Glen Robson</a></span>"]})])
-canvas = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/918ecd18c2592080851777620de9bcb5-gottingen",
-                                        id="https://iiif.io/api/cookbook/recipe/0007-string-formats/canvas/p1")
-canvas.items[0].id = "https://iiif.io/api/cookbook/recipe/0007-string-formats/page/p1/1"
-canvas.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0007-string-formats/annotation/p0001-image"
-
-print(manifest.json(indent=2))
+--8<-- "docs/recipes/scripts/0007-string-formats-method1.py"
 ```
diff --git a/docs/recipes/0008-rights.md b/docs/recipes/0008-rights.md
index aa2d4e1..09e1351 100644
--- a/docs/recipes/0008-rights.md
+++ b/docs/recipes/0008-rights.md
@@ -1,24 +1,10 @@
 # Rights statement
-### Recipe: [https://iiif.io/api/cookbook/recipe/0008-rights/](https://iiif.io/api/cookbook/recipe/0008-rights/)
-### JSON-LD: [https://iiif.io/api/cookbook/recipe/0008-rights/manifest.json](https://iiif.io/api/cookbook/recipe/0008-rights/manifest.json)
+|              | **Cookbook URLs**                                                                                                              |
+|--------------|--------------------------------------------------------------------------------------------------------------------------------|
+| **Recipe:**  | [https://iiif.io/api/cookbook/recipe/0008-rights/](https://iiif.io/api/cookbook/recipe/0008-rights/)                           |
+| **JSON-LD:** | [https://iiif.io/api/cookbook/recipe/0008-rights/manifest.json](https://iiif.io/api/cookbook/recipe/0008-rights/manifest.json) |
 
-## Method 1 - Building the object directly and making use of the AutoLang config
+### Method 1 - Building the object directly and making use of the AutoLang config
 ```python
-from iiif_prezi3 import Manifest, KeyValueString, config
-
-config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
-
-manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0008-rights/manifest.json",
-                    label="Picture of Göttingen taken during the 2019 IIIF Conference",
-                    summary="<p>Picture taken by the <a href=\"https://github.com/glenrobson\">IIIF Technical Coordinator</a></p>",
-                    rights="http://creativecommons.org/licenses/by-sa/3.0/",
-                    requiredStatement=KeyValueString(label="Attribution",
-                                                     value="<span>Glen Robson, IIIF Technical Coordinator. <a href=\"https://creativecommons.org/licenses/by-sa/3.0\">CC BY-SA 3.0</a> <img src=\"https://licensebuttons.net/l/by-sa/3.0/88x31.png\"/></span>"),
-                    metadata=[KeyValueString(label="Author", value={"none": ["<span><a href='https://github.com/glenrobson'>Glen Robson</a></span>"]})])
-canvas = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/918ecd18c2592080851777620de9bcb5-gottingen",
-                                        id="https://iiif.io/api/cookbook/recipe/0008-rights/canvas/p1")
-canvas.items[0].id = "https://iiif.io/api/cookbook/recipe/0008-rights/page/p1/1"
-canvas.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0008-rights/annotation/p0001-image"
-
-print(manifest.json(indent=2))
+--8<-- "docs/recipes/scripts/0008-rights-method1.py"
 ```
diff --git a/docs/recipes/0009-book-1.md b/docs/recipes/0009-book-1.md
index b31d1e4..31fe75b 100644
--- a/docs/recipes/0009-book-1.md
+++ b/docs/recipes/0009-book-1.md
@@ -1,45 +1,10 @@
 # Simple Manifest - Book
-### Recipe: [https://iiif.io/api/cookbook/recipe/0009-book-1/](https://iiif.io/api/cookbook/recipe/0009-book-1/)
-### JSON-LD: [https://iiif.io/api/cookbook/recipe/0009-book-1/manifest.json](https://iiif.io/api/cookbook/recipe/0009-book-1/manifest.json)
+|              | **Cookbook URLs**                                                                                                              |
+|--------------|--------------------------------------------------------------------------------------------------------------------------------|
+| **Recipe:**  | [https://iiif.io/api/cookbook/recipe/0009-book-1/](https://iiif.io/api/cookbook/recipe/0009-book-1/)                           |
+| **JSON-LD:** | [https://iiif.io/api/cookbook/recipe/0009-book-1/manifest.json](https://iiif.io/api/cookbook/recipe/0009-book-1/manifest.json) |
 
-## Method 1 - Setting the `behavior` property during object construction
+### Method 1 - Setting the `behavior` property during object construction
 ```python
-from iiif_prezi3 import Manifest, config
-
-config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
-
-manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0009-book-1/manifest.json",
-                    label="Simple Manifest - Book",
-                    behavior=["paged"])
-canvas1 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/59d09e6773341f28ea166e9f3c1e674f-gallica_ark_12148_bpt6k1526005v_f18",
-                                         id="https://iiif.io/api/cookbook/recipe/0009-book-1/canvas/p1",
-                                         label="Blank page")
-canvas1.items[0].id = "https://iiif.io/api/cookbook/recipe/0009-book-1/page/p1/1"
-canvas1.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0009-book-1/annotation/p0001-image"
-
-canvas2 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/59d09e6773341f28ea166e9f3c1e674f-gallica_ark_12148_bpt6k1526005v_f19",
-                                         id="https://iiif.io/api/cookbook/recipe/0009-book-1/canvas/p2",
-                                         label="Frontispiece")
-canvas2.items[0].id = "https://iiif.io/api/cookbook/recipe/0009-book-1/page/p2/1"
-canvas2.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0009-book-1/annotation/p0002-image"
-
-canvas3 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/59d09e6773341f28ea166e9f3c1e674f-gallica_ark_12148_bpt6k1526005v_f20",
-                                         id="https://iiif.io/api/cookbook/recipe/0009-book-1/canvas/p3",
-                                         label="Title page")
-canvas3.items[0].id = "https://iiif.io/api/cookbook/recipe/0009-book-1/page/p3/1"
-canvas3.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0009-book-1/annotation/p0003-image"
-
-canvas4 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/59d09e6773341f28ea166e9f3c1e674f-gallica_ark_12148_bpt6k1526005v_f21",
-                                         id="https://iiif.io/api/cookbook/recipe/0009-book-1/canvas/p4",
-                                         label="Blank page")
-canvas4.items[0].id = "https://iiif.io/api/cookbook/recipe/0009-book-1/page/p4/1"
-canvas4.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0009-book-1/annotation/p0004-image"
-
-canvas5 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/59d09e6773341f28ea166e9f3c1e674f-gallica_ark_12148_bpt6k1526005v_f22",
-                                         id="https://iiif.io/api/cookbook/recipe/0009-book-1/canvas/p5",
-                                         label="Bookplate")
-canvas5.items[0].id = "https://iiif.io/api/cookbook/recipe/0009-book-1/page/p5/1"
-canvas5.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0009-book-1/annotation/p0005-image"
-
-print(manifest.json(indent=2))
+--8<-- "docs/recipes/scripts/0009-book-1-method1.py"
 ```
diff --git a/docs/recipes/0010-book-2-viewing-direction.md b/docs/recipes/0010-book-2-viewing-direction.md
index e389f87..786a857 100644
--- a/docs/recipes/0010-book-2-viewing-direction.md
+++ b/docs/recipes/0010-book-2-viewing-direction.md
@@ -1,86 +1,17 @@
 # Viewing direction and Its Effect on Navigation
-### Recipe: [https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/](https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/)
-### JSON-LD Example 1: [https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/manifest-rtl.json](https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/manifest-rtl.json)
-### JSON-LD Example 2: [https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/manifest-ttb.json](https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/manifest-ttb.json)
-
-## Method 1 - Setting the `viewingDirection` property during object construction
-### Example 1
+|                        | **Cookbook URLs**                                                                                                                                                          |
+|------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **Recipe:**            | [https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/](https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/)                                   |
+| **JSON-LD Example 1:** | [https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/manifest-rtl.json](https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/manifest-rtl.json) |
+| **JSON-LD Example 2:** | [https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/manifest-ttb.json](https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/manifest-ttb.json) |
+
+### Method 1 - Setting the `viewingDirection` property during object construction
+#### Example 1
 ```python
-from iiif_prezi3 import Manifest, config
-
-config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
-
-manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/manifest-rtl.json",
-                    label="Book with Right-to-Left Viewing Direction",
-                    summary="Playbill for \"Akiba gongen kaisen-banashi,\" \"Futatsu chōchō kuruwa nikki\" and \"Godairiki koi no fūjime\" performed at the Chikugo Theater in Osaka from the fifth month of Kaei 2 (May, 1849); main actors: Gadō Kataoka II, Ebizō Ichikawa VI, Kitō Sawamura II, Daigorō Mimasu IV and Karoku Nakamura I; on front cover: producer Mominosuke Ichikawa's crest.",
-                    viewingDirection="right-to-left")
-
-canvas1 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/4f92cceb12dd53b52433425ce44308c7-ucla_bib1987273_no001_rs_001",
-                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/p1",
-                                         label="front cover")
-canvas1.items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/p1/1"
-canvas1.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/p0001-image"
-
-canvas2 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/4f92cceb12dd53b52433425ce44308c7-ucla_bib1987273_no001_rs_002",
-                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/p2",
-                                         label="pages 1-2")
-canvas2.items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/p2/1"
-canvas2.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/p0002-image"
-
-canvas3 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/4f92cceb12dd53b52433425ce44308c7-ucla_bib1987273_no001_rs_003",
-                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/p3",
-                                         label="pages 3-4")
-canvas3.items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/p3/1"
-canvas3.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/p0003-image"
-
-canvas4 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/4f92cceb12dd53b52433425ce44308c7-ucla_bib1987273_no001_rs_004",
-                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/p4",
-                                         label="pages 5-6")
-canvas4.items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/p4/1"
-canvas4.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/p0004-image"
-
-canvas5 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/4f92cceb12dd53b52433425ce44308c7-ucla_bib1987273_no001_rs_005",
-                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/p5",
-                                         label="back cover")
-canvas5.items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/p5/1"
-canvas5.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/p0005-image"
-
-print(manifest.json(indent=2))
+--8<-- "docs/recipes/scripts/0010-book-2-viewing-direction-method1-example1.py"
 ```
 
-### Example 2
+#### Example 2
 ```python
-from iiif_prezi3 import Manifest, config
-
-config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
-
-manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/manifest-ttb.json",
-                    label="Diary with Top-to-Bottom Viewing Direction",
-                    summary="William Lewis Sachtleben was an American long-distance cyclist who rode across Asia from Istanbul to Peking in 1891 to 1892 with Thomas Gaskell Allen Jr., his classmate from Washington University. This was part of a longer journey that began the day after they had graduated from college, when they travelled to New York and on to Liverpool; in all they travelled 15,044 miles by bicycle, 'the longest continuous land journey ever made around the world' as reported in their book <cite>Across Asia on a bicycle</cite> (1895). Sachtleben documented his travels with photographs and diaries, the latter of which he numbered sequentially. The diary of notebook 'No. 10' covers a portion of their journey through the Armenian area of Turkey from April 12 to May 9 (there is a 2-page reading list at the end). During this time they rode from Ankara (Angora in the diary) to Sivas, where they stayed for ten days while Allen had a bout of typhoid fever, and the first half of a ten-day excursion to Merzifon (Mersovan in the diary), taken by Sachtleben to give Allen additional time to recover.",
-                    viewingDirection="top-to-bottom")
-canvas1 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/9ee11092dfd2782634f5e8e2c87c16d5-uclamss_1841_diary_07_02",
-                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/v1",
-                                         label="image 1")
-canvas1.items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/v1/1"
-canvas1.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/v0001-image"
-
-canvas2 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/9ee11092dfd2782634f5e8e2c87c16d5-uclamss_1841_diary_07_03",
-                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/v2",
-                                         label="image 2")
-canvas2.items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/v2/1"
-canvas2.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/v0002-image"
-
-canvas3 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/9ee11092dfd2782634f5e8e2c87c16d5-uclamss_1841_diary_07_04",
-                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/v3",
-                                         label="image 3")
-canvas3.items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/v3/1"
-canvas3.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/v0003-image"
-
-canvas4 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/9ee11092dfd2782634f5e8e2c87c16d5-uclamss_1841_diary_07_05",
-                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/v4",
-                                         label="image 4")
-canvas4.items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/v4/1"
-canvas4.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/v0004-image"
-
-print(manifest.json(indent=2))
+--8<-- "docs/recipes/scripts/0010-book-2-viewing-direction-method1-example2.py"
 ```
diff --git a/docs/recipes/0011-book-3-behavior.md b/docs/recipes/0011-book-3-behavior.md
index 475a32c..ba4eb53 100644
--- a/docs/recipes/0011-book-3-behavior.md
+++ b/docs/recipes/0011-book-3-behavior.md
@@ -1,76 +1,17 @@
 # Book 'behavior' Variations (continuous, individuals)
-### Recipe: [https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/](https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/)
-### JSON-LD Use Case 1: [https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/manifest-continuous.json](https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/manifest-continuous.json)
-### JSON-LD Use Case 2: [https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/manifest-individuals.json](https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/manifest-individuals.json)
-
-## Method 1 - Setting the `behaviour` property during object construction
-### Use Case 1
+|                         | **Cookbook URLs**                                                                                                                                                        |
+|-------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **Recipe:**             | [https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/](https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/)                                                   |
+| **JSON-LD Use Case 1:** | [https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/manifest-continuous.json](https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/manifest-continuous.json)   |
+| **JSON-LD Use Case 2:** | [https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/manifest-individuals.json](https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/manifest-individuals.json) |
+
+### Method 1 - Setting the `behavior` property during object construction
+#### Use Case 1
 ```python
-from iiif_prezi3 import Manifest, config
-
-config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
-manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/manifest-continuous.json",
-                    label={"gez": ["Ms. 21 Māzemurā Dāwit, Asmat [መዝሙረ ዳዊት]"]},
-                    behaviour=["continuous"])
-canvas1 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/8c169124171e6b2253b698a22a938f07-21198-zz001hbmd9_1300412_master",
-                                         id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/canvas/s1",
-                                         label="Section 1 [Recto]")
-canvas1.items[0].id = "https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/page/s1/1"
-canvas1.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/annotation/s0001-image"
-
-canvas2 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/8c169124171e6b2253b698a22a938f07-21198-zz001hbmft_1300418_master",
-                                         id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/canvas/s2",
-                                         label="Section 2 [Recto]")
-canvas2.items[0].id = "https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/page/s2/1"
-canvas2.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/annotation/s0002-image"
-
-canvas3 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/8c169124171e6b2253b698a22a938f07-21198-zz001hbmgb_1300426_master",
-                                         id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/canvas/s3",
-                                         label="Section 3 [Recto]")
-canvas3.items[0].id = "https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/page/s3/1"
-canvas3.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/annotation/s0003-image"
-
-canvas4 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/8c169124171e6b2253b698a22a938f07-21198-zz001hbmhv_1300436_master",
-                                         id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/canvas/s4",
-                                         label="Section 4 [Recto]")
-canvas4.items[0].id = "https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/page/s4/1"
-canvas4.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/annotation/s0004-image"
-
-print(manifest.json(indent=2))
+--8<-- "docs/recipes/scripts/0011-book-3-behavior-method1-usecase1.py"
 ```
 
-### Use Case 2
+#### Use Case 2
 ```python
-from iiif_prezi3 import Manifest, config
-
-config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
-manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/manifest-individuals.json",
-                    label={"ca": ["[Conoximent de las orines] Ihesus, Ihesus. En nom de Deu et dela beneyeta sa mare e de tots los angels i archangels e de tots los sants e santes de paradis yo micer Johannes comense aquest libre de reseptes en l’ayn Mi 466."]},
-                    behaviour=["individuals"])
-
-canvas1 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/85a96c630f077e6ac6cb984f1b752bbf-0-21198-zz00022840-1-master",
-                                         id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/canvas/v1",
-                                         label="inside cover; 1r")
-canvas1.items[0].id = "https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/page/v1/1"
-canvas1.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/annotation/v0001-image"
-
-canvas2 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/85a96c630f077e6ac6cb984f1b752bbf-1-21198-zz00022882-1-master",
-                                         id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/canvas/v2",
-                                         label="2v, 3r")
-canvas2.items[0].id = "https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/page/v2/1"
-canvas2.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/annotation/v0002-image"
-
-canvas3 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/85a96c630f077e6ac6cb984f1b752bbf-2-21198-zz000228b3-1-master",
-                                         id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/canvas/v3",
-                                         label="3v, 4r")
-canvas3.items[0].id = "https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/page/v3/1"
-canvas3.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/annotation/v0003-image"
-
-canvas4 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/85a96c630f077e6ac6cb984f1b752bbf-3-21198-zz000228d4-1-master",
-                                         id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/canvas/v4",
-                                         label="4v, 5r")
-canvas4.items[0].id = "https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/page/v4/1"
-canvas4.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/annotation/v0004-image"
-
-print(manifest.json(indent=2))
+--8<-- "docs/recipes/scripts/0011-book-3-behavior-method1-usecase2.py"
 ```
\ No newline at end of file
diff --git a/docs/recipes/0015-start.md b/docs/recipes/0015-start.md
index 59dfb62..9435b10 100644
--- a/docs/recipes/0015-start.md
+++ b/docs/recipes/0015-start.md
@@ -1,36 +1,10 @@
 # Begin playback at a specific point - Time-based media
-### Recipe: [https://iiif.io/api/cookbook/recipe/0015-start/](https://iiif.io/api/cookbook/recipe/0015-start/)
-### JSON-LD: [https://iiif.io/api/cookbook/recipe/0015-start/manifest.json](https://iiif.io/api/cookbook/recipe/0015-start/manifest.json)
+|              | **Cookbook URLs**                                                                                                            |
+|--------------|------------------------------------------------------------------------------------------------------------------------------|
+| **Recipe:**  | [https://iiif.io/api/cookbook/recipe/0015-start/](https://iiif.io/api/cookbook/recipe/0015-start/)                           |
+| **JSON-LD:** | [https://iiif.io/api/cookbook/recipe/0015-start/manifest.json](https://iiif.io/api/cookbook/recipe/0015-start/manifest.json) |
 
-## Method 1 - Building the `start` structure using the `SpecificResource` class
+### Method 1 - Building the `start` structure using the `SpecificResource` class
 ```python
-from iiif_prezi3 import Manifest, KeyValueString, ResourceItem, AnnotationPage, Annotation, SpecificResource, config
-
-config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
-manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0015-start/manifest.json",
-                    label="Video of a 30-minute digital clock",
-                    rights="http://creativecommons.org/licenses/by/3.0/",
-                    requiredStatement=KeyValueString(label="Attribution",
-                                                     value="<span>The video was created by <a href='https://www.youtube.com/watch?v=Lsq0FiXjGHg'>DrLex1</a> and was released using a <a href='https://creativecommons.org/licenses/by/3.0/'>Creative Commons Attribution license</a></span>")
-                    )
-
-canvas = manifest.make_canvas(id="https://iiif.io/api/cookbook/recipe/0015-start/canvas/segment1", duration=1801.055)
-anno_body = ResourceItem(id="https://fixtures.iiif.io/video/indiana/30-minute-clock/medium/30-minute-clock.mp4",
-                         type="Video",
-                         format="video/mp4",
-                         duration= 1801.055)
-anno_page = AnnotationPage(id="https://iiif.io/api/cookbook/recipe/0015-start/annotation/segment1/page")
-anno = Annotation(id="https://iiif.io/api/cookbook/recipe/0015-start/annotation/segment1-video",
-                  motivation="painting",
-                  body=anno_body,
-                  target=canvas.id)
-
-anno_page.add_item(anno)
-canvas.add_item(anno_page)
-
-manifest.start = SpecificResource(id="https://iiif.io/api/cookbook/recipe/0015-start/canvas-start/segment1",
-                                  source=canvas.id,
-                                  selector={"type": "PointSelector", "t": 120.5})
-
-print(manifest.json(indent=2))
+--8<-- "docs/recipes/scripts/0015-start-method1.py"
 ```
diff --git a/docs/recipes/0017-transcription-av.md b/docs/recipes/0017-transcription-av.md
new file mode 100644
index 0000000..e0499b8
--- /dev/null
+++ b/docs/recipes/0017-transcription-av.md
@@ -0,0 +1,10 @@
+# Providing Access to Transcript Files of A/V Content
+|              | **Cookbook URLs** |
+|--------------|-------------------|
+| **Recipe:**  | [https://iiif.io/api/cookbook/recipe/0017-transcription-av/](https://iiif.io/api/cookbook/recipe/0017-transcription-av/) |
+| **JSON-LD:** | [https://iiif.io/api/cookbook/recipe/0017-transcription-av/manifest.json](https://iiif.io/api/cookbook/recipe/0017-transcription-av/manifest.json) |
+
+### Method 1 - Building the `rendering` structure using the `ExternalItem` class
+```python
+--8<-- "docs/recipes/scripts/0017-transcription-av-method1.py"
+```
\ No newline at end of file
diff --git a/docs/recipes/0019-html-in-annotations.md b/docs/recipes/0019-html-in-annotations.md
index 58e817e..c130850 100644
--- a/docs/recipes/0019-html-in-annotations.md
+++ b/docs/recipes/0019-html-in-annotations.md
@@ -1,26 +1,10 @@
 # HTML in Annotations
-### Recipe: [https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/](https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/)
-### JSON-LD: [https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/manifest.json](https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/manifest.json)
+|              | **Cookbook URLs**                                                                                                                                        |
+|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **Recipe:**  | [https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/](https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/)                           |
+| **JSON-LD:** | [https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/manifest.json](https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/manifest.json) |
 
-## Method 1 - Construct an Annotation using the `make_annotation` helper and a dictionary of the `body` properties
+### Method 1 - Construct an Annotation using the `make_annotation` helper and a dictionary of the `body` properties
 ```python
-from iiif_prezi3 import Manifest
-
-manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/manifest.json",
-                    label={"en": ["Picture of Göttingen taken during the 2019 IIIF Conference"]})
-canvas = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/918ecd18c2592080851777620de9bcb5-gottingen",
-                               id="https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/canvas-1")
-canvas.items[0].id = "https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/canvas-1/annopage-1"
-canvas.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/canvas-1/annopage-1/anno-1"
-
-anno = canvas.make_annotation(id="https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/canvas-1/annopage-2/anno-1",
-                              motivation="commenting",
-                              body= {"type": "TextualBody",
-                                     "language": "de",
-                                     "format": "text/html",
-                                     "value": "<p>Göttinger Marktplatz mit <a href='https://de.wikipedia.org/wiki/G%C3%A4nseliesel-Brunnen_(G%C3%B6ttingen)'>Gänseliesel Brunnen <img src='https://en.wikipedia.org/static/images/project-logos/enwiki.png' alt='Wikipedia logo'></a></p>"},
-                              target=canvas.id)
-canvas.annotations[0].id = "https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/canvas-1/annopage-2"
-
-print(manifest.json(indent=2))
+--8<-- "docs/recipes/scripts/0019-html-in-annotations-method1.py"
 ```
diff --git a/docs/recipes/0021-tagging.md b/docs/recipes/0021-tagging.md
index e5b4d90..86c3e40 100644
--- a/docs/recipes/0021-tagging.md
+++ b/docs/recipes/0021-tagging.md
@@ -1,26 +1,10 @@
 # Simple Annotation — Tagging
-### Recipe: [https://iiif.io/api/cookbook/recipe/0021-tagging/](https://iiif.io/api/cookbook/recipe/0021-tagging/)
-### JSON-LD: [https://iiif.io/api/cookbook/recipe/0021-tagging/manifest.json](https://iiif.io/api/cookbook/recipe/0021-tagging/manifest.json)
+|              | **Cookbook URLs**                                                                                                                |
+|--------------|----------------------------------------------------------------------------------------------------------------------------------|
+| **Recipe:**  | [https://iiif.io/api/cookbook/recipe/0021-tagging/](https://iiif.io/api/cookbook/recipe/0021-tagging/)                           |
+| **JSON-LD:** | [https://iiif.io/api/cookbook/recipe/0021-tagging/manifest.json](https://iiif.io/api/cookbook/recipe/0021-tagging/manifest.json) |
 
-## Method 1 - Construct an Annotation using the `make_annotation` helper and a dictionary of the `body` properties
+### Method 1 - Construct an Annotation using the `make_annotation` helper and a dictionary of the `body` properties
 ```python
-from iiif_prezi3 import Manifest
-
-manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0021-tagging/manifest.json",
-                    label={"en": ["Picture of Göttingen taken during the 2019 IIIF Conference"]})
-canvas = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/918ecd18c2592080851777620de9bcb5-gottingen",
-                               id="https://iiif.io/api/cookbook/recipe/0021-tagging/canvas/p1")
-canvas.items[0].id = "https://iiif.io/api/cookbook/recipe/0021-tagging/page/p1/1"
-canvas.items[0].items[0].id = "https://iiif.io/api/cookbook/recipe/0021-tagging/annotation/p0001-image"
-
-anno = canvas.make_annotation(id="https://iiif.io/api/cookbook/recipe/0021-tagging/annotation/p0002-ta",
-                              motivation="tagging",
-                              body= {"type": "TextualBody",
-                                     "language": "de",
-                                     "format": "text/plain",
-                                     "value": "Gänseliesel-Brunnen"},
-                              target=canvas.id + "#xywh=265,661,1260,1239")
-canvas.annotations[0].id = "https://iiif.io/api/cookbook/recipe/0021-tagging/page/p2/1"
-
-print(manifest.json(indent=2))
+--8<-- "docs/recipes/scripts/0021-tagging-method1.py"
 ```
diff --git a/docs/recipes/0230-navdate.md b/docs/recipes/0230-navdate.md
new file mode 100644
index 0000000..855b9dd
--- /dev/null
+++ b/docs/recipes/0230-navdate.md
@@ -0,0 +1,37 @@
+# Navigation by Chronology
+|                                     | **Cookbook URLs** |
+|-------------------------------------|-------------------|
+| **Recipe:**                         | [https://iiif.io/api/cookbook/recipe/0230-navdate/](https://iiif.io/api/cookbook/recipe/0230-navdate/) |
+| **JSON-LD Example 1 - 1986 Map:**   | [https://iiif.io/api/cookbook/recipe/0230-navdate/navdate_map_2-manifest.json](https://iiif.io/api/cookbook/recipe/0230-navdate/navdate_map_2-manifest.json) |
+| **JSON-LD Example 2 - 1987 Map:**   | [https://iiif.io/api/cookbook/recipe/0230-navdate/navdate_map_1-manifest.json](https://iiif.io/api/cookbook/recipe/0230-navdate/navdate_map_1-manifest.json) |
+| **JSON-LD Example 3 - Collection:** | [https://iiif.io/api/cookbook/recipe/0230-navdate/navdate-collection.json](https://iiif.io/api/cookbook/recipe/0230-navdate/navdate-collection.json) |
+
+### Method 1 - Setting the `navDate` property during object construction using a `datetime` object
+#### Example 1 - 1986 Map
+```python
+--8<-- "docs/recipes/scripts/0230-navdate-method1-example1.py"
+```
+#### Example 2 - 1987 Map
+```python
+--8<-- "docs/recipes/scripts/0230-navdate-method1-example2.py"
+```
+#### Example 3 - Collection
+Here we can make use of the fact that `iiif-prezi3` will automatically turn a Manifest into a reference when it is added to a Collection object.
+```python
+--8<-- "docs/recipes/scripts/0230-navdate-method1-example3.py"
+```
+
+### Method 2 - Setting the `navDate` property with a string
+#### Example 1 - 1986 Map
+```python
+--8<-- "docs/recipes/scripts/0230-navdate-method2-example1.py"
+```
+#### Example 2 - 1987 Map
+```python
+--8<-- "docs/recipes/scripts/0230-navdate-method2-example2.py"
+```
+#### Example 3 - Collection
+To show the different possible approaches, here we will build the Collection object manually using the `ManifestRef` class.
+```python
+--8<-- "docs/recipes/scripts/0230-navdate-method2-example3.py"
+```
\ No newline at end of file
diff --git a/docs/recipes/index.md b/docs/recipes/index.md
new file mode 100644
index 0000000..b68297a
--- /dev/null
+++ b/docs/recipes/index.md
@@ -0,0 +1,6 @@
+# Cookbook Recipes
+This section of the documentation attempts to provide a "learn by example" resource, by reproducing the [IIIF Cookbook](https://iiif.io/api/cookbook) recipes using the `iiif-prezi3` library.
+
+Where possible, the helper methods and other conveniences of `iiif-prezi3` are leveraged, with secondary examples showing alternate methods of creating the recipe JSON.
+
+If you would like to contribute to this section, please see the [Cookbook recipe examples issue](https://github.com/iiif-prezi/iiif-prezi3/issues/129) in the project's GitHub repository.
\ No newline at end of file
diff --git a/docs/recipes/scripts/0001-mvm-image-method1.py b/docs/recipes/scripts/0001-mvm-image-method1.py
new file mode 100644
index 0000000..7fb1a2c
--- /dev/null
+++ b/docs/recipes/scripts/0001-mvm-image-method1.py
@@ -0,0 +1,15 @@
+from iiif_prezi3 import Manifest, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0001-mvm-image/manifest.json", label="Image 1")
+canvas = manifest.make_canvas(id="https://iiif.io/api/cookbook/recipe/0001-mvm-image/canvas/p1", height=1800, width=1200)
+anno_page = canvas.add_image(image_url="http://iiif.io/api/presentation/2.1/example/fixtures/resources/page1-full.png",
+                             anno_page_id="https://iiif.io/api/cookbook/recipe/0001-mvm-image/page/p1/1",
+                             anno_id="https://iiif.io/api/cookbook/recipe/0001-mvm-image/annotation/p0001-image",
+                             format="image/png",
+                             height=1800,
+                             width=1200
+                             )
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0001-mvm-image-method2.py b/docs/recipes/scripts/0001-mvm-image-method2.py
new file mode 100644
index 0000000..206c309
--- /dev/null
+++ b/docs/recipes/scripts/0001-mvm-image-method2.py
@@ -0,0 +1,21 @@
+from iiif_prezi3 import Manifest, Canvas, AnnotationPage, Annotation, ResourceItem, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0001-mvm-image/manifest.json", label="Image 1")
+canvas = Canvas(id="https://iiif.io/api/cookbook/recipe/0001-mvm-image/canvas/p1", height=1800, width=1200)
+anno_body = ResourceItem(id="http://iiif.io/api/presentation/2.1/example/fixtures/resources/page1-full.png",
+                         type="Image",
+                         format="image/png",
+                         height=1800,
+                         width=1200)
+anno_page = AnnotationPage(id="https://iiif.io/api/cookbook/recipe/0001-mvm-image/page/p1/1")
+anno = Annotation(id="https://iiif.io/api/cookbook/recipe/0001-mvm-image/annotation/p0001-image",
+                  motivation="painting",
+                  body=anno_body,
+                  target=canvas.id)
+anno_page.add_item(anno)
+canvas.add_item(anno_page)
+manifest.add_item(canvas)
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0002-mvm-audio-method1.py b/docs/recipes/scripts/0002-mvm-audio-method1.py
new file mode 100644
index 0000000..eab04fc
--- /dev/null
+++ b/docs/recipes/scripts/0002-mvm-audio-method1.py
@@ -0,0 +1,19 @@
+from iiif_prezi3 import Manifest, AnnotationPage, Annotation, ResourceItem, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0002-mvm-audio/manifest.json", label="Simplest Audio Example 1")
+canvas = manifest.make_canvas(id="https://iiif.io/api/cookbook/recipe/0002-mvm-audio/canvas", duration=1985.024)
+anno_body = ResourceItem(id="https://fixtures.iiif.io/audio/indiana/mahler-symphony-3/CD1/medium/128Kbps.mp4",
+                         type="Sound",
+                         format="audio/mp4",
+                         duration=1985.024)
+anno_page = AnnotationPage(id="https://iiif.io/api/cookbook/recipe/0002-mvm-audio/canvas/page")
+anno = Annotation(id="https://iiif.io/api/cookbook/recipe/0002-mvm-audio/canvas/page/annotation",
+                  motivation="painting",
+                  body=anno_body,
+                  target=canvas.id)
+anno_page.add_item(anno)
+canvas.add_item(anno_page)
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0003-mvm-video-method1.py b/docs/recipes/scripts/0003-mvm-video-method1.py
new file mode 100644
index 0000000..9cbed02
--- /dev/null
+++ b/docs/recipes/scripts/0003-mvm-video-method1.py
@@ -0,0 +1,24 @@
+from iiif_prezi3 import Manifest, AnnotationPage, Annotation, ResourceItem, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0003-mvm-video/manifest.json", label="Video Example 3")
+canvas = manifest.make_canvas(id="https://iiif.io/api/cookbook/recipe/0003-mvm-video/canvas")
+anno_body = ResourceItem(id="https://fixtures.iiif.io/video/indiana/lunchroom_manners/high/lunchroom_manners_1024kb.mp4",
+                         type="Video",
+                         format="video/mp4")
+anno_page = AnnotationPage(id="https://iiif.io/api/cookbook/recipe/0003-mvm-video/canvas/page")
+anno = Annotation(id="https://iiif.io/api/cookbook/recipe/0003-mvm-video/canvas/page/annotation",
+                  motivation="painting",
+                  body=anno_body,
+                  target=canvas.id)
+
+hwd = {"height": 360, "width": 480, "duration": 572.034}
+anno_body.set_hwd(**hwd)
+hwd["width"] = 640
+canvas.set_hwd(**hwd)
+
+anno_page.add_item(anno)
+canvas.add_item(anno_page)
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0004-canvas-size-method1.py b/docs/recipes/scripts/0004-canvas-size-method1.py
new file mode 100644
index 0000000..78fd977
--- /dev/null
+++ b/docs/recipes/scripts/0004-canvas-size-method1.py
@@ -0,0 +1,22 @@
+from iiif_prezi3 import Manifest, AnnotationPage, Annotation, ResourceItem, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0004-canvas-size/manifest.json", label="Still image from an opera performance at Indiana University")
+canvas = manifest.make_canvas(id="https://iiif.io/api/cookbook/recipe/0004-canvas-size/canvas/p1")
+anno_body = ResourceItem(id="https://fixtures.iiif.io/video/indiana/donizetti-elixir/act1-thumbnail.png",
+                         type="Image",
+                         format="image/png")
+anno_page = AnnotationPage(id="https://iiif.io/api/cookbook/recipe/0004-canvas-size/page/p1/1")
+anno = Annotation(id="https://iiif.io/api/cookbook/recipe/0004-canvas-size/annotation/p0001-image",
+                  motivation="painting",
+                  body=anno_body,
+                  target=canvas.id)
+
+anno_body.set_hwd(height=360, width=640)
+canvas.set_hwd(height=1080, width=1920)
+
+anno_page.add_item(anno)
+canvas.add_item(anno_page)
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0005-image-service-method1.py b/docs/recipes/scripts/0005-image-service-method1.py
new file mode 100644
index 0000000..60895cd
--- /dev/null
+++ b/docs/recipes/scripts/0005-image-service-method1.py
@@ -0,0 +1,12 @@
+from iiif_prezi3 import Manifest, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0005-image-service/manifest.json", label="Picture of Göttingen taken during the 2019 IIIF Conference")
+canvas = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/918ecd18c2592080851777620de9bcb5-gottingen",
+                                        id="https://iiif.io/api/cookbook/recipe/0005-image-service/canvas/p1",
+                                        label="Canvas with a single IIIF image",
+                                        anno_id="https://iiif.io/api/cookbook/recipe/0005-image-service/annotation/p0001-image",
+                                        anno_page_id="https://iiif.io/api/cookbook/recipe/0005-image-service/page/p1/1")
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0006-text-language-method1.py b/docs/recipes/scripts/0006-text-language-method1.py
new file mode 100644
index 0000000..577557f
--- /dev/null
+++ b/docs/recipes/scripts/0006-text-language-method1.py
@@ -0,0 +1,20 @@
+from iiif_prezi3 import Manifest, KeyValueString
+
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0006-text-language/manifest.json",
+                    label={"en": ["Whistler's Mother"], "fr": ["La Mère de Whistler"]})
+manifest.metadata = [
+    KeyValueString(label={"en": ["Creator"], "fr": ["Auteur"]}, value="Whistler, James Abbott McNeill"),
+    KeyValueString(label={"en": ["Subject"], "fr": ["Sujet"]},
+                   value={"en": ["McNeill Anna Matilda, mother of Whistler (1804-1881)"],
+                          "fr": ["McNeill Anna Matilda, mère de Whistler (1804-1881)"]})
+]
+manifest.summary = {"en": ["Arrangement in Grey and Black No. 1, also called Portrait of the Artist's Mother."],
+                    "fr": ["Arrangement en gris et noir n°1, also called Portrait de la mère de l'artiste."]}
+manifest.requiredStatement = KeyValueString(label={"en": ["Held By"], "fr": ["Détenu par"]}, value="Musée d'Orsay, Paris, France")
+
+canvas = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/329817fc8a251a01c393f517d8a17d87-Whistlers_Mother",
+                                        id="https://iiif.io/api/cookbook/recipe/0006-text-language/canvas/p1",
+                                        anno_id="https://iiif.io/api/cookbook/recipe/0006-text-language/annotation/p0001-image",
+                                        anno_page_id="https://iiif.io/api/cookbook/recipe/0006-text-language/page/p1/1")
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0007-string-formats-method1.py b/docs/recipes/scripts/0007-string-formats-method1.py
new file mode 100644
index 0000000..fa41df7
--- /dev/null
+++ b/docs/recipes/scripts/0007-string-formats-method1.py
@@ -0,0 +1,17 @@
+from iiif_prezi3 import Manifest, KeyValueString, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0007-string-formats/manifest.json",
+                    label="Picture of Göttingen taken during the 2019 IIIF Conference",
+                    summary="<p>Picture taken by the <a href=\"https://github.com/glenrobson\">IIIF Technical Coordinator</a></p>",
+                    rights="http://creativecommons.org/licenses/by-sa/3.0/",
+                    requiredStatement=KeyValueString(label="Attribution",
+                                                     value="<span>Glen Robson, IIIF Technical Coordinator. <a href=\"https://creativecommons.org/licenses/by-sa/3.0\">CC BY-SA 3.0</a> <img src=\"https://licensebuttons.net/l/by-sa/3.0/88x31.png\"/></span>"),
+                    metadata=[KeyValueString(label="Author", value={"none": ["<span><a href='https://github.com/glenrobson'>Glen Robson</a></span>"]})])
+canvas = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/918ecd18c2592080851777620de9bcb5-gottingen",
+                                        id="https://iiif.io/api/cookbook/recipe/0007-string-formats/canvas/p1",
+                                        anno_id="https://iiif.io/api/cookbook/recipe/0007-string-formats/annotation/p0001-image",
+                                        anno_page_id="https://iiif.io/api/cookbook/recipe/0007-string-formats/page/p1/1")
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0008-rights-method1.py b/docs/recipes/scripts/0008-rights-method1.py
new file mode 100644
index 0000000..620e8d1
--- /dev/null
+++ b/docs/recipes/scripts/0008-rights-method1.py
@@ -0,0 +1,18 @@
+from iiif_prezi3 import Manifest, KeyValueString, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0008-rights/manifest.json",
+                    label="Picture of Göttingen taken during the 2019 IIIF Conference",
+                    summary="<p>Picture taken by the <a href=\"https://github.com/glenrobson\">IIIF Technical Coordinator</a></p>",
+                    rights="http://creativecommons.org/licenses/by-sa/3.0/",
+                    requiredStatement=KeyValueString(label="Attribution",
+                                                     value="<span>Glen Robson, IIIF Technical Coordinator. <a href=\"https://creativecommons.org/licenses/by-sa/3.0\">CC BY-SA 3.0</a> <a href=\"https://creativecommons.org/licenses/by-sa/3.0\" title\"CC BY-SA 3.0\"><img src=\"https://licensebuttons.net/l/by-sa/3.0/88x31.png\"/></a></span>")
+                    )
+
+canvas = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/918ecd18c2592080851777620de9bcb5-gottingen",
+                                        id="https://iiif.io/api/cookbook/recipe/0008-rights/canvas/p1",
+                                        anno_id="https://iiif.io/api/cookbook/recipe/0008-rights/annotation/p0001-image",
+                                        anno_page_id="https://iiif.io/api/cookbook/recipe/0008-rights/page/p1/1")
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0009-book-1-method1.py b/docs/recipes/scripts/0009-book-1-method1.py
new file mode 100644
index 0000000..9a6282d
--- /dev/null
+++ b/docs/recipes/scripts/0009-book-1-method1.py
@@ -0,0 +1,38 @@
+from iiif_prezi3 import Manifest, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0009-book-1/manifest.json",
+                    label="Simple Manifest - Book",
+                    behavior=["paged"])
+canvas1 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/59d09e6773341f28ea166e9f3c1e674f-gallica_ark_12148_bpt6k1526005v_f18",
+                                         id="https://iiif.io/api/cookbook/recipe/0009-book-1/canvas/p1",
+                                         label="Blank page",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0009-book-1/annotation/p0001-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0009-book-1/page/p1/1")
+
+canvas2 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/59d09e6773341f28ea166e9f3c1e674f-gallica_ark_12148_bpt6k1526005v_f19",
+                                         id="https://iiif.io/api/cookbook/recipe/0009-book-1/canvas/p2",
+                                         label="Frontispiece",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0009-book-1/annotation/p0002-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0009-book-1/page/p2/1")
+
+canvas3 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/59d09e6773341f28ea166e9f3c1e674f-gallica_ark_12148_bpt6k1526005v_f20",
+                                         id="https://iiif.io/api/cookbook/recipe/0009-book-1/canvas/p3",
+                                         label="Title page",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0009-book-1/annotation/p0003-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0009-book-1/page/p3/1")
+
+canvas4 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/59d09e6773341f28ea166e9f3c1e674f-gallica_ark_12148_bpt6k1526005v_f21",
+                                         id="https://iiif.io/api/cookbook/recipe/0009-book-1/canvas/p4",
+                                         label="Blank page",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0009-book-1/annotation/p0004-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0009-book-1/page/p4/1")
+
+canvas5 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/59d09e6773341f28ea166e9f3c1e674f-gallica_ark_12148_bpt6k1526005v_f22",
+                                         id="https://iiif.io/api/cookbook/recipe/0009-book-1/canvas/p5",
+                                         label="Bookplate",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0009-book-1/annotation/p0005-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0009-book-1/page/p5/1")
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0010-book-2-viewing-direction-method1-example1.py b/docs/recipes/scripts/0010-book-2-viewing-direction-method1-example1.py
new file mode 100644
index 0000000..c9e046d
--- /dev/null
+++ b/docs/recipes/scripts/0010-book-2-viewing-direction-method1-example1.py
@@ -0,0 +1,40 @@
+from iiif_prezi3 import Manifest, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/manifest-rtl.json",
+                    label="Book with Right-to-Left Viewing Direction",
+                    summary="Playbill for \"Akiba gongen kaisen-banashi,\" \"Futatsu chōchō kuruwa nikki\" and \"Godairiki koi no fūjime\" performed at the Chikugo Theater in Osaka from the fifth month of Kaei 2 (May, 1849); main actors: Gadō Kataoka II, Ebizō Ichikawa VI, Kitō Sawamura II, Daigorō Mimasu IV and Karoku Nakamura I; on front cover: producer Mominosuke Ichikawa's crest.",
+                    viewingDirection="right-to-left")
+
+canvas1 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/4f92cceb12dd53b52433425ce44308c7-ucla_bib1987273_no001_rs_001",
+                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/p1",
+                                         label="front cover",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/p0001-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/p1/1")
+
+canvas2 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/4f92cceb12dd53b52433425ce44308c7-ucla_bib1987273_no001_rs_002",
+                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/p2",
+                                         label="pages 1–2",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/p0002-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/p2/1")
+
+canvas3 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/4f92cceb12dd53b52433425ce44308c7-ucla_bib1987273_no001_rs_003",
+                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/p3",
+                                         label="pages 3–4",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/p0003-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/p3/1")
+
+canvas4 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/4f92cceb12dd53b52433425ce44308c7-ucla_bib1987273_no001_rs_004",
+                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/p4",
+                                         label="pages 5–6",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/p0004-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/p4/1")
+
+canvas5 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/4f92cceb12dd53b52433425ce44308c7-ucla_bib1987273_no001_rs_005",
+                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/p5",
+                                         label="back cover",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/p0005-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/p5/1")
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0010-book-2-viewing-direction-method1-example2.py b/docs/recipes/scripts/0010-book-2-viewing-direction-method1-example2.py
new file mode 100644
index 0000000..64f4dd5
--- /dev/null
+++ b/docs/recipes/scripts/0010-book-2-viewing-direction-method1-example2.py
@@ -0,0 +1,33 @@
+from iiif_prezi3 import Manifest, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/manifest-ttb.json",
+                    label="Diary with Top-to-Bottom Viewing Direction",
+                    summary="William Lewis Sachtleben was an American long-distance cyclist who rode across Asia from Istanbul to Peking in 1891 to 1892 with Thomas Gaskell Allen Jr., his classmate from Washington University. This was part of a longer journey that began the day after they had graduated from college, when they travelled to New York and on to Liverpool; in all they travelled 15,044 miles by bicycle, 'the longest continuous land journey ever made around the world' as reported in their book <cite>Across Asia on a bicycle</cite> (1895). Sachtleben documented his travels with photographs and diaries, the latter of which he numbered sequentially. The diary of notebook 'No. 10' covers a portion of their journey through the Armenian area of Turkey from April 12 to May 9 (there is a 2-page reading list at the end). During this time they rode from Ankara (Angora in the diary) to Sivas, where they stayed for ten days while Allen had a bout of typhoid fever, and the first half of a ten-day excursion to Merzifon (Mersovan in the diary), taken by Sachtleben to give Allen additional time to recover.",
+                    viewingDirection="top-to-bottom")
+canvas1 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/9ee11092dfd2782634f5e8e2c87c16d5-uclamss_1841_diary_07_02",
+                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/v1",
+                                         label="image 1",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/v0001-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/v1/1")
+
+canvas2 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/9ee11092dfd2782634f5e8e2c87c16d5-uclamss_1841_diary_07_03",
+                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/v2",
+                                         label="image 2",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/v0002-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/v2/1")
+
+canvas3 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/9ee11092dfd2782634f5e8e2c87c16d5-uclamss_1841_diary_07_04",
+                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/v3",
+                                         label="image 3",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/v0003-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/v3/1")
+
+canvas4 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/9ee11092dfd2782634f5e8e2c87c16d5-uclamss_1841_diary_07_05",
+                                         id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/canvas/v4",
+                                         label="image 4",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/annotation/v0004-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/page/v4/1")
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0011-book-3-behavior-method1-usecase1.py b/docs/recipes/scripts/0011-book-3-behavior-method1-usecase1.py
new file mode 100644
index 0000000..6ec9a98
--- /dev/null
+++ b/docs/recipes/scripts/0011-book-3-behavior-method1-usecase1.py
@@ -0,0 +1,31 @@
+from iiif_prezi3 import Manifest, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/manifest-continuous.json",
+                    label={"gez": ["Ms. 21 Māzemurā Dāwit, Asmat [መዝሙረ ዳዊት]"]},
+                    behavior=["continuous"])
+canvas1 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/8c169124171e6b2253b698a22a938f07-21198-zz001hbmd9_1300412_master",
+                                         id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/canvas/s1",
+                                         label="Section 1 [Recto]",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/annotation/s0001-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/page/s1/1")
+
+canvas2 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/8c169124171e6b2253b698a22a938f07-21198-zz001hbmft_1300418_master",
+                                         id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/canvas/s2",
+                                         label="Section 2 [Recto]",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/annotation/s0002-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/page/s2/1")
+
+canvas3 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/8c169124171e6b2253b698a22a938f07-21198-zz001hbmgb_1300426_master",
+                                         id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/canvas/s3",
+                                         label="Section 3 [Recto]",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/annotation/s0003-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/page/s3/1")
+
+canvas4 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/8c169124171e6b2253b698a22a938f07-21198-zz001hbmhv_1300436_master",
+                                         id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/canvas/s4",
+                                         label="Section 4 [Recto]",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/annotation/s0004-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/page/s4/1")
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0011-book-3-behavior-method1-usecase2.py b/docs/recipes/scripts/0011-book-3-behavior-method1-usecase2.py
new file mode 100644
index 0000000..4f58c1b
--- /dev/null
+++ b/docs/recipes/scripts/0011-book-3-behavior-method1-usecase2.py
@@ -0,0 +1,32 @@
+from iiif_prezi3 import Manifest, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/manifest-individuals.json",
+                    label={"ca": ["[Conoximent de las orines] Ihesus, Ihesus. En nom de Deu et dela beneyeta sa mare e de tots los angels i archangels e de tots los sants e santes de paradis yo micer Johannes comense aquest libre de reseptes en l’ayn Mi 466."]},
+                    behavior=["individuals"])
+
+canvas1 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/85a96c630f077e6ac6cb984f1b752bbf-0-21198-zz00022840-1-master",
+                                         id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/canvas/v1",
+                                         label="inside cover; 1r",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/annotation/v0001-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/page/v1/1")
+
+canvas2 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/85a96c630f077e6ac6cb984f1b752bbf-1-21198-zz00022882-1-master",
+                                         id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/canvas/v2",
+                                         label="2v, 3r",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/annotation/v0002-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/page/v2/1")
+
+canvas3 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/85a96c630f077e6ac6cb984f1b752bbf-2-21198-zz000228b3-1-master",
+                                         id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/canvas/v3",
+                                         label="3v, 4r",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/annotation/v0003-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/page/v3/1")
+
+canvas4 = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/85a96c630f077e6ac6cb984f1b752bbf-3-21198-zz000228d4-1-master",
+                                         id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/canvas/v4",
+                                         label="4v, 5r",
+                                         anno_id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/annotation/v0004-image",
+                                         anno_page_id="https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/page/v4/1")
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0015-start-method1.py b/docs/recipes/scripts/0015-start-method1.py
new file mode 100644
index 0000000..225e119
--- /dev/null
+++ b/docs/recipes/scripts/0015-start-method1.py
@@ -0,0 +1,29 @@
+from iiif_prezi3 import Manifest, KeyValueString, ResourceItem, AnnotationPage, Annotation, SpecificResource, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0015-start/manifest.json",
+                    label="Video of a 30-minute digital clock",
+                    rights="http://creativecommons.org/licenses/by/3.0/",
+                    requiredStatement=KeyValueString(label="Attribution",
+                                                     value="<span>The video was created by <a href='https://www.youtube.com/watch?v=Lsq0FiXjGHg'>DrLex1</a> and was released using a <a href='https://creativecommons.org/licenses/by/3.0/'>Creative Commons Attribution license</a></span>")
+                    )
+
+canvas = manifest.make_canvas(id="https://iiif.io/api/cookbook/recipe/0015-start/canvas/segment1", duration=1801.055)
+anno_body = ResourceItem(id="https://fixtures.iiif.io/video/indiana/30-minute-clock/medium/30-minute-clock.mp4",
+                         type="Video",
+                         format="video/mp4",
+                         duration=1801.055)
+anno_page = AnnotationPage(id="https://iiif.io/api/cookbook/recipe/0015-start/annotation/segment1/page")
+anno = Annotation(id="https://iiif.io/api/cookbook/recipe/0015-start/annotation/segment1-video",
+                  motivation="painting",
+                  body=anno_body,
+                  target=canvas.id)
+
+anno_page.add_item(anno)
+canvas.add_item(anno_page)
+
+manifest.start = SpecificResource(id="https://iiif.io/api/cookbook/recipe/0015-start/canvas-start/segment1",
+                                  source=canvas.id,
+                                  selector={"type": "PointSelector", "t": 120.5})
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0017-transcription-av-method1.py b/docs/recipes/scripts/0017-transcription-av-method1.py
new file mode 100644
index 0000000..1d24ec4
--- /dev/null
+++ b/docs/recipes/scripts/0017-transcription-av-method1.py
@@ -0,0 +1,31 @@
+from iiif_prezi3 import Manifest, ExternalItem, ResourceItem, AnnotationPage, Annotation, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0017-transcription-av/manifest.json",
+                    label="Volleyball for Boys")
+
+canvas = manifest.make_canvas(id="https://iiif.io/api/cookbook/recipe/0017-transcription-av/canvas")
+anno_body = ResourceItem(id="https://fixtures.iiif.io/video/indiana/volleyball/high/volleyball-for-boys.mp4",
+                         type="Video",
+                         format="video/mp4")
+anno_page = AnnotationPage(id="https://iiif.io/api/cookbook/recipe/0017-transcription-av/canvas/page")
+anno = Annotation(id="https://iiif.io/api/cookbook/recipe/0017-transcription-av/canvas/page/annotation",
+                  motivation="painting",
+                  body=anno_body,
+                  target=canvas.id)
+
+hwd = {"height": 1080, "width": 1920, "duration": 662.037}
+anno_body.set_hwd(**hwd)
+canvas.set_hwd(**hwd)
+
+anno_page.add_item(anno)
+canvas.add_item(anno_page)
+
+rendering = ExternalItem(id="https://fixtures.iiif.io/video/indiana/volleyball/volleyball.txt",
+                         type="Text",
+                         label="Transcript",
+                         format="text/txt")
+
+canvas.rendering = [rendering]
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0019-html-in-annotations-method1.py b/docs/recipes/scripts/0019-html-in-annotations-method1.py
new file mode 100644
index 0000000..f32e618
--- /dev/null
+++ b/docs/recipes/scripts/0019-html-in-annotations-method1.py
@@ -0,0 +1,19 @@
+from iiif_prezi3 import Manifest
+
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/manifest.json",
+                    label={"en": ["Picture of Göttingen taken during the 2019 IIIF Conference"]})
+canvas = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/918ecd18c2592080851777620de9bcb5-gottingen",
+                                        id="https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/canvas-1",
+                                        anno_id="https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/canvas-1/annopage-1/anno-1",
+                                        anno_page_id="https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/canvas-1/annopage-1")
+
+anno = canvas.make_annotation(id="https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/canvas-1/annopage-2/anno-1",
+                              motivation="commenting",
+                              body={"type": "TextualBody",
+                                    "language": "de",
+                                    "format": "text/html",
+                                    "value": "<p>Göttinger Marktplatz mit <a href='https://de.wikipedia.org/wiki/G%C3%A4nseliesel-Brunnen_(G%C3%B6ttingen)'>Gänseliesel Brunnen <img src='https://en.wikipedia.org/static/images/project-logos/enwiki.png' alt='Wikipedia logo'></a></p>"},
+                              target=canvas.id,
+                              anno_page_id="https://iiif.io/api/cookbook/recipe/0019-html-in-annotations/canvas-1/annopage-2")
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0021-tagging-method1.py b/docs/recipes/scripts/0021-tagging-method1.py
new file mode 100644
index 0000000..213fce4
--- /dev/null
+++ b/docs/recipes/scripts/0021-tagging-method1.py
@@ -0,0 +1,19 @@
+from iiif_prezi3 import Manifest
+
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0021-tagging/manifest.json",
+                    label={"en": ["Picture of Göttingen taken during the 2019 IIIF Conference"]})
+canvas = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/918ecd18c2592080851777620de9bcb5-gottingen",
+                                        id="https://iiif.io/api/cookbook/recipe/0021-tagging/canvas/p1",
+                                        anno_id="https://iiif.io/api/cookbook/recipe/0021-tagging/annotation/p0001-image",
+                                        anno_page_id="https://iiif.io/api/cookbook/recipe/0021-tagging/page/p1/1")
+
+anno = canvas.make_annotation(id="https://iiif.io/api/cookbook/recipe/0021-tagging/annotation/p0002-tag",
+                              motivation="tagging",
+                              body={"type": "TextualBody",
+                                    "language": "de",
+                                    "format": "text/plain",
+                                    "value": "Gänseliesel-Brunnen"},
+                              target=canvas.id + "#xywh=265,661,1260,1239",
+                              anno_page_id="https://iiif.io/api/cookbook/recipe/0021-tagging/page/p2/1")
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0230-navdate-method1-example1.py b/docs/recipes/scripts/0230-navdate-method1-example1.py
new file mode 100644
index 0000000..312984f
--- /dev/null
+++ b/docs/recipes/scripts/0230-navdate-method1-example1.py
@@ -0,0 +1,19 @@
+from iiif_prezi3 import Manifest, config
+from datetime import datetime, timezone
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+
+# n.b: You MUST set `tzinfo` as the Prezi3 Specification requires a timezone, and the default `datetime` does not have one.
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0230-navdate/navdate_map_2-manifest.json",
+                    label="1986 Chesapeake and Ohio Canal, Washington, D.C., Maryland, West Virginia, official map and guide",
+                    navDate=datetime(1986, 1, 1, tzinfo=timezone.utc))
+canvas = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/43153e2ec7531f14dd1c9b2fc401678a-87691274-1986",
+                                        id="https://iiif.io/api/cookbook/recipe/0230-navdate/canvas/p1",
+                                        label="1986 Map, recto and verso, with a date of publication",
+                                        anno_id="https://iiif.io/api/cookbook/recipe/0230-navdate/annotation/p0001-image",
+                                        anno_page_id="https://iiif.io/api/cookbook/recipe/0230-navdate/page/p1/1")
+
+# This is a workaround for an inconsistency in the Cookbook JSON - see https://github.com/IIIF/cookbook-recipes/issues/376
+canvas.items[0].items[0].body.service[0].id = "https://iiif.io/api/image/3.0/example/reference/43153e2ec7531f14dd1c9b2fc401678a-87691274-1986/"
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0230-navdate-method1-example2.py b/docs/recipes/scripts/0230-navdate-method1-example2.py
new file mode 100644
index 0000000..5e3cbcd
--- /dev/null
+++ b/docs/recipes/scripts/0230-navdate-method1-example2.py
@@ -0,0 +1,19 @@
+from iiif_prezi3 import Manifest, config
+from datetime import datetime, timezone
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+
+# n.b: You MUST set `tzinfo` as the Prezi3 Specification requires a timezone, and the default `datetime` does not have one.
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0230-navdate/navdate_map_1-manifest.json",
+                    label="1987 Chesapeake and Ohio Canal, Washington, D.C., Maryland, West Virginia, official map and guide",
+                    navDate=datetime(1987, 1, 1, tzinfo=timezone.utc))
+canvas = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/43153e2ec7531f14dd1c9b2fc401678a-88695674",
+                                        id="https://iiif.io/api/cookbook/recipe/0230-navdate/canvas/p1",
+                                        label="1987 Map, recto and verso, with a date of publication",
+                                        anno_id="https://iiif.io/api/cookbook/recipe/0230-navdate/annotation/p0001-image",
+                                        anno_page_id="https://iiif.io/api/cookbook/recipe/0230-navdate/page/p1/1")
+
+# This is a workaround for an inconsistency in the Cookbook JSON - see https://github.com/IIIF/cookbook-recipes/issues/376
+canvas.items[0].items[0].body.service[0].id = "https://iiif.io/api/image/3.0/example/reference/43153e2ec7531f14dd1c9b2fc401678a-88695674/"
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0230-navdate-method1-example3.py b/docs/recipes/scripts/0230-navdate-method1-example3.py
new file mode 100644
index 0000000..9c47161
--- /dev/null
+++ b/docs/recipes/scripts/0230-navdate-method1-example3.py
@@ -0,0 +1,42 @@
+from iiif_prezi3 import Collection, Manifest, ResourceItem, config
+from datetime import datetime, timezone
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+
+# n.b: You MUST set `tzinfo` as the Prezi3 Specification requires a timezone, and the default `datetime` does not have one.
+manifest1986 = Manifest(id="https://iiif.io/api/cookbook/recipe/0230-navdate/navdate_map_2-manifest.json",
+                        label="1986 Chesapeake and Ohio Canal, Washington, D.C., Maryland, West Virginia, official map and guide",
+                        navDate=datetime(1986, 1, 1, tzinfo=timezone.utc))
+canvas1986 = manifest1986.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/43153e2ec7531f14dd1c9b2fc401678a-87691274-1986",
+                                                id="https://iiif.io/api/cookbook/recipe/0230-navdate/canvas/p1",
+                                                label="1986 Map, recto and verso, with a date of publication",
+                                                anno_id="https://iiif.io/api/cookbook/recipe/0230-navdate/annotation/p0001-image",
+                                                anno_page_id="https://iiif.io/api/cookbook/recipe/0230-navdate/page/p1/1")
+
+manifest1987 = Manifest(id="https://iiif.io/api/cookbook/recipe/0230-navdate/navdate_map_1-manifest.json",
+                        label="1987 Chesapeake and Ohio Canal, Washington, D.C., Maryland, West Virginia, official map and guide",
+                        navDate=datetime(1987, 1, 1, tzinfo=timezone.utc))
+canvas1987 = manifest1987.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/43153e2ec7531f14dd1c9b2fc401678a-88695674",
+                                                id="https://iiif.io/api/cookbook/recipe/0230-navdate/canvas/p1",
+                                                label="1987 Map, recto and verso, with a date of publication",
+                                                anno_id="https://iiif.io/api/cookbook/recipe/0230-navdate/annotation/p0001-image",
+                                                anno_page_id="https://iiif.io/api/cookbook/recipe/0230-navdate/page/p1/1")
+
+collection = Collection(id="https://iiif.io/api/cookbook/recipe/0230-navdate/navdate-collection.json",
+                        label="Chesapeake and Ohio Canal map and guide pamphlets")
+thumbnail = ResourceItem(id="https://iiif.io/api/image/3.0/example/reference/43153e2ec7531f14dd1c9b2fc401678a-88695674/full/max/0/default.jpg",
+                         type="Image",
+                         format="image/jpeg",
+                         height=300,
+                         width=221)
+thumbnail.make_service(id="https://iiif.io/api/image/3.0/example/reference/43153e2ec7531f14dd1c9b2fc401678a-88695674",
+                       type="ImageService3",
+                       profile="level1")
+collection.thumbnail = [thumbnail]
+
+collection.add_item(manifest1986)
+collection.add_item(manifest1987)
+collection.items[0].navDate = manifest1986.navDate
+collection.items[1].navDate = manifest1987.navDate
+
+print(collection.json(indent=2))
diff --git a/docs/recipes/scripts/0230-navdate-method2-example1.py b/docs/recipes/scripts/0230-navdate-method2-example1.py
new file mode 100644
index 0000000..2b8b8d8
--- /dev/null
+++ b/docs/recipes/scripts/0230-navdate-method2-example1.py
@@ -0,0 +1,18 @@
+from iiif_prezi3 import Manifest, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0230-navdate/navdate_map_2-manifest.json",
+                    label="1986 Chesapeake and Ohio Canal, Washington, D.C., Maryland, West Virginia, official map and guide",
+                    navDate="1986-01-01T00:00:00Z")
+
+canvas = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/43153e2ec7531f14dd1c9b2fc401678a-87691274-1986",
+                                        id="https://iiif.io/api/cookbook/recipe/0230-navdate/canvas/p1",
+                                        label="1986 Map, recto and verso, with a date of publication",
+                                        anno_id="https://iiif.io/api/cookbook/recipe/0230-navdate/annotation/p0001-image",
+                                        anno_page_id="https://iiif.io/api/cookbook/recipe/0230-navdate/page/p1/1")
+
+# This is a workaround for an inconsistency in the Cookbook JSON - see https://github.com/IIIF/cookbook-recipes/issues/376
+canvas.items[0].items[0].body.service[0].id = "https://iiif.io/api/image/3.0/example/reference/43153e2ec7531f14dd1c9b2fc401678a-87691274-1986/"
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0230-navdate-method2-example2.py b/docs/recipes/scripts/0230-navdate-method2-example2.py
new file mode 100644
index 0000000..38b10c0
--- /dev/null
+++ b/docs/recipes/scripts/0230-navdate-method2-example2.py
@@ -0,0 +1,17 @@
+from iiif_prezi3 import Manifest, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+
+manifest = Manifest(id="https://iiif.io/api/cookbook/recipe/0230-navdate/navdate_map_1-manifest.json",
+                    label="1987 Chesapeake and Ohio Canal, Washington, D.C., Maryland, West Virginia, official map and guide",
+                    navDate="1987-01-01T00:00:00Z")
+canvas = manifest.make_canvas_from_iiif(url="https://iiif.io/api/image/3.0/example/reference/43153e2ec7531f14dd1c9b2fc401678a-88695674",
+                                        id="https://iiif.io/api/cookbook/recipe/0230-navdate/canvas/p1",
+                                        label="1987 Map, recto and verso, with a date of publication",
+                                        anno_id="https://iiif.io/api/cookbook/recipe/0230-navdate/annotation/p0001-image",
+                                        anno_page_id="https://iiif.io/api/cookbook/recipe/0230-navdate/page/p1/1")
+
+# This is a workaround for an inconsistency in the Cookbook JSON - see https://github.com/IIIF/cookbook-recipes/issues/376
+canvas.items[0].items[0].body.service[0].id = "https://iiif.io/api/image/3.0/example/reference/43153e2ec7531f14dd1c9b2fc401678a-88695674/"
+
+print(manifest.json(indent=2))
diff --git a/docs/recipes/scripts/0230-navdate-method2-example3.py b/docs/recipes/scripts/0230-navdate-method2-example3.py
new file mode 100644
index 0000000..9a6881e
--- /dev/null
+++ b/docs/recipes/scripts/0230-navdate-method2-example3.py
@@ -0,0 +1,30 @@
+from iiif_prezi3 import Collection, ManifestRef, ResourceItem, config
+
+config.configs['helpers.auto_fields.AutoLang'].auto_lang = "en"
+
+collection = Collection(id="https://iiif.io/api/cookbook/recipe/0230-navdate/navdate-collection.json",
+                        label="Chesapeake and Ohio Canal map and guide pamphlets")
+thumbnail = ResourceItem(id="https://iiif.io/api/image/3.0/example/reference/43153e2ec7531f14dd1c9b2fc401678a-88695674/full/max/0/default.jpg",
+                         type="Image",
+                         format="image/jpeg",
+                         height=300,
+                         width=221)
+thumbnail.make_service(id="https://iiif.io/api/image/3.0/example/reference/43153e2ec7531f14dd1c9b2fc401678a-88695674",
+                       type="ImageService3",
+                       profile="level1")
+collection.thumbnail = [thumbnail]
+
+manifest1986 = ManifestRef(id="https://iiif.io/api/cookbook/recipe/0230-navdate/navdate_map_2-manifest.json",
+                           type="Manifest",
+                           label="1986 Chesapeake and Ohio Canal, Washington, D.C., Maryland, West Virginia, official map and guide",
+                           navDate="1986-01-01T00:00:00+00:00")
+
+manifest1987 = ManifestRef(id="https://iiif.io/api/cookbook/recipe/0230-navdate/navdate_map_1-manifest.json",
+                           type="Manifest",
+                           label="1987 Chesapeake and Ohio Canal, Washington, D.C., Maryland, West Virginia, official map and guide",
+                           navDate="1987-01-01T00:00:00+00:00")
+
+collection.add_item(manifest1986)
+collection.add_item(manifest1987)
+
+print(collection.json(indent=2))
diff --git a/iiif_prezi3/base.py b/iiif_prezi3/base.py
index db3310b..fd99a68 100644
--- a/iiif_prezi3/base.py
+++ b/iiif_prezi3/base.py
@@ -1,6 +1,7 @@
 import json
 
 from pydantic import AnyUrl, BaseModel
+from pydantic.json import pydantic_encoder
 
 
 class Base(BaseModel):
@@ -60,7 +61,7 @@ def jsonld(self, **kwargs):
 
         json_kwargs = dict([(arg, kwargs[arg]) for arg in kwargs.keys() if arg not in pydantic_args + excluded_args])
         return json.dumps({"@context": "http://iiif.io/api/presentation/3/context.json",
-                           **self.dict(exclude_unset=False, exclude_defaults=False, exclude_none=True, by_alias=True, **dict_kwargs)}, **json_kwargs)
+                           **self.dict(exclude_unset=False, exclude_defaults=False, exclude_none=True, by_alias=True, **dict_kwargs)}, default=pydantic_encoder, **json_kwargs)
 
     def jsonld_dict(self, **kwargs):
         pydantic_args = ["include", "exclude", "encoder"]
diff --git a/iiif_prezi3/helpers/auto_fields.py b/iiif_prezi3/helpers/auto_fields.py
index be28184..1135ec7 100644
--- a/iiif_prezi3/helpers/auto_fields.py
+++ b/iiif_prezi3/helpers/auto_fields.py
@@ -2,7 +2,7 @@
 
 from ..config.config import Config, register_config
 from ..skeleton import (Annotation, AnnotationCollection, AnnotationPage,
-                        Canvas, Collection, KeyValueString, Manifest, Range)
+                        Canvas, Class, Collection, KeyValueString, Manifest, Range, Reference)
 
 
 class AutoConfig(Config):
@@ -152,5 +152,5 @@ def manipulate_value(self, what, value=None):
 
 # Set up some obvious defaults
 ai.register_on_class(Collection, Manifest, Canvas, Range, Annotation, AnnotationPage, AnnotationCollection)
-al.register_on_class(Collection, Manifest, Canvas, Range, AnnotationCollection, KeyValueString)
+al.register_on_class(Collection, Manifest, Canvas, Range, AnnotationCollection, KeyValueString, Class, Reference)
 ait.register_on_class(Canvas, Range)
diff --git a/iiif_prezi3/skeleton.py b/iiif_prezi3/skeleton.py
index b6b662d..ea8807d 100644
--- a/iiif_prezi3/skeleton.py
+++ b/iiif_prezi3/skeleton.py
@@ -418,6 +418,9 @@ class CollectionRef(Reference):
 class ManifestRef(Reference):
     type: Optional[constr(regex=r'^Manifest$')] = None
 
+    class Config:
+        extra = Extra.allow
+
 
 class CanvasRef(Reference):
     type: Optional[constr(regex=r'^Canvas$')] = None
diff --git a/mkdocs.yml b/mkdocs.yml
index ad8fe53..d5039fc 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -8,6 +8,9 @@ nav:
         - 'generate-schema.md'
         - 'write-helper-method.md'
         - code.md
+    - Cookbook Recipes:
+        - 'Introduction': 'recipes/index.md'
+        - ... | flat | recipes/0*.md
 
 theme:
   name: material
@@ -17,9 +20,11 @@ markdown_extensions:
   - pymdownx.highlight:
       use_pygments: true
   - pymdownx.superfences
+  - pymdownx.snippets
 
 plugins:
   - search
+  - awesome-pages
   - mkdocstrings:
       default_handler: python
       handlers:
diff --git a/setup.py b/setup.py
index e5f2d32..76f4944 100644
--- a/setup.py
+++ b/setup.py
@@ -22,7 +22,8 @@
     "mkdocs >=1.4.0, <2.0.0",
     "mkdocs-material >=8.0.0, <9.0.0",
     "mkdocstrings-python >=0.7.0, <1.0.0",
-    "griffe >=0.25.2, <1.0.0"
+    "griffe >=0.25.2, <1.0.0",
+    "mkdocs-awesome-pages-plugin >=2.8.0, <3.0.0"
 ]
 
 DEV_REQUIREMENTS = [
@@ -32,7 +33,8 @@
     "flake8-docstrings >=1.6.0, <2.0.0",
     "flake8-isort >=4.1.1, <5.0.0",
     "tox >=3.25.0, <4.0.0",
-    "Pillow >=9.1.1, <10.0.0"
+    "Pillow >=9.1.1, <10.0.0",
+    "deepdiff >=6.2.2, <7.0.0"
 ]
 
 # Setting up
diff --git a/utils/modify_skeleton.py b/utils/modify_skeleton.py
index 60b6ceb..fe18a31 100644
--- a/utils/modify_skeleton.py
+++ b/utils/modify_skeleton.py
@@ -10,6 +10,13 @@
         "type": "replace",
         "find": "class ServiceItem1(Base):\n    _id: Id = Field(..., alias='@id')\n    _type: str = Field(..., alias='@type')",
         "replace": "class ServiceItem1(Base):\n    id: Id = Field(..., alias='@id')\n    type: str = Field(..., alias='@type')"
+    },
+    {
+        "description": "Allow extra properties on ManifestRef",
+        "type": "insert",
+        "before": "class ManifestRef(Reference):\n    type: Optional[constr(regex=r'^Manifest$')] = None\n",
+        "after": "\n\nclass CanvasRef(Reference):",
+        "data": "\n    class Config:\n        extra = Extra.allow\n"
     }
 ]
 
@@ -33,7 +40,7 @@ def process_change(skeleton, change):
             if after == -1:
                 print("After string not found - skipping change")
             else:
-                skeleton = skeleton[:start] + change["data"] + skeleton[after:]
+                skeleton = skeleton[:start+len(change["before"])] + change["data"] + skeleton[after:]
 
     return skeleton
 


Test patch:
diff --git a/utils/test_cookbook.py b/utils/test_cookbook.py
new file mode 100644
index 0000000..06a4b2a
--- /dev/null
+++ b/utils/test_cookbook.py
@@ -0,0 +1,190 @@
+import argparse
+import json
+import os
+import re
+import shlex
+import subprocess
+
+import requests
+from deepdiff import DeepDiff
+
+# Recipe file regular expressions
+JSON_RE = re.compile(r"\*\*JSON-LD:? ?(?P<type>[A-Za-z ]*) ?(?P<number>\d*)?.*:?\*\* *\| \[(?P<url>.*)\]")
+PYTHON_RE = re.compile(r'--8<-- "(?P<loc>.*-(?P<method>method\d+)-?(?P<type>\w*)?.*\.py)"')
+
+
+def build_json_dict(matches):
+    result = {}
+    for match in matches:
+        flat = f"{match.group('type').replace(' ','').lower()}{match.group('number')}"
+        if flat == "":
+            flat = "general"
+        if flat in result:
+            result[flat]["json"].append(match.group('url'))
+        else:
+            result[flat] = {"json": [match.group('url')]}
+    return result
+
+
+def get_json(json_file):
+    # Flatten the directory name of the Cookbook recipe into the target filename
+    flat = "-".join(json_file.split("/")[-2:])
+    json_path = f"{args.cache_directory}/{flat}"
+
+    # Download the file if necessary
+    if args.ignore_cache or not os.path.exists(json_path):
+        response = requests.get(json_file)
+        if response.status_code == 200:
+            with open(json_path, "wb") as out:
+                out.write(response.content)
+        else:
+            print(f"ERROR: Could not download {json_file} - Status Code {response.status_code}")
+            return None
+
+    # Parse and return the JSON
+    try:
+        json_data = json.load(open(json_path, 'r'))
+        return json_data
+    except Exception as e:
+        print(f"ERROR: Could not parse JSON from {json_path} - {e}")
+        return None
+
+
+def run_test(python_file, json_file):
+    # Get the target JSON from cache or download
+    target = get_json(json_file)
+    if not target:
+        return False
+
+    # Run the Python script, catch the output and try and parse the JSON
+    try:
+        output = subprocess.run(shlex.split(f"python ../{python_file}"), capture_output=True, check=True)
+    except subprocess.CalledProcessError as e:
+        print(f"ERROR: Running script {python_file} - {e}")
+        return False
+
+    try:
+        j = json.loads(output.stdout)
+    except json.JSONDecodeError as e:
+        print(f"ERROR: Could not parse valid JSON from output of script {python_file} - {e}")
+        return False
+
+    # Diff the generated JSON against the target
+    result = DeepDiff(target, j)
+    if result == {}:
+        return True
+    else:
+        print(f"FAILURE: The output of script {python_file} did not match the Cookbook JSON {json_file}")
+        if args.verbose >= 1:
+            print("===Differences===")
+            print(result)
+            print("=================")
+        return False
+
+
+def process_recipe(file):  # noqa: C901
+    results = []
+
+    # Sanity check the file
+    if not file.endswith(".md"):
+        print(f"ERROR: {file} does not have a .md extension")
+        return False
+
+    # Read recipe file
+    try:
+        recipe_data = open(file, "r").read()
+    except Exception as e:
+        print(f"ERROR: Could not read {file} - {e}")
+        return False
+
+    # Find JSON-LD and Python links
+    json_links = JSON_RE.finditer(recipe_data)
+    python_links = PYTHON_RE.finditer(recipe_data)
+
+    # Convert JSON files into a dictionary for type matching
+    json_dict = build_json_dict(json_links)
+
+    # Walkthrough each Python link found and try to match it to a JSON file
+    for p in python_links:
+        t = p.group('type')
+        if t == "":
+            t = "general"
+        if t in json_dict:
+            if "python" in json_dict[t]:
+                json_dict[t]["python"].append(p.group('loc'))
+            else:
+                json_dict[t]["python"] = [p.group('loc')]
+        else:
+            if args.fail_missing:
+                print(f"ERROR: {p.group('loc')} could not be matched to a Cookbook JSON in {file}")
+                return False
+            else:
+                if args.verbose >= 1:
+                    print(f"WARNING: {p.group('loc')} could not be matched to a Cookbook JSON in {file}")
+
+    # Check all the JSON file groups have associated scripts and run them
+    for t in json_dict:
+        if "python" not in json_dict[t]:
+            if args.fail_missing:
+                print(f"ERROR: JSON group {t} does not have any associated Python scripts in {file}")
+                return False
+            else:
+                if args.verbose >= 1:
+                    print(f"WARNING: JSON group {t} does not have any associated Python scripts in {file}")
+
+        else:
+            # Loop the JSON files and run each associated test script
+            for j in json_dict[t]["json"]:
+                for p in json_dict[t]["python"]:
+                    result = run_test(p, j)
+                    results.append(result)
+
+                    # Fail out if necessary
+                    if not result and args.fail_fast:
+                        exit(1)
+
+    return all(results)
+
+
+if __name__ == "__main__":
+    global args
+
+    parser = argparse.ArgumentParser()
+    parser.add_argument('recipe_file', nargs="+", help="The recipe(s) to test")
+    parser.add_argument('-v', "--verbose", action="count", default=0, help="Increase output verbosity")
+    parser.add_argument("-y", action="store_true", help="Bypass 'Are you sure?' question")
+    parser.add_argument("--ignore-cache", action="store_true", help="Always download Cookbook JSON files")
+    # parser.add_argument("--no-cache", action="store_true", help="Remove Cookbook JSON files after use")
+    parser.add_argument("--fail-fast", action="store_true", help="Fail the whole run as soon as one test fails")
+    parser.add_argument("--fail-missing", action="store_true", help="Fail an individual recipe if any of the JSON files are missing implementations in code or any of the Python files can't be matched to a Cookbook JSON")
+    parser.add_argument("--cache-directory", type=str, help="Cache directory for Cookbook JSON files (default: .cache)", default=".cache")
+    args = parser.parse_args()
+    # print(args)
+
+    # Perform security check
+    if not args.y:
+        response = input("This script will execute what could be arbitrary Python code from files in the docs/recipes/scripts directory. Are you sure you want to continue? (y/n) ")
+        if response.lower() != "y":
+            exit()
+
+    results = []
+
+    # Make the cache directory if it does not exist
+    os.makedirs(args.cache_directory, exist_ok=True)
+
+    # Check the validity of the input files and call the runner
+    for file in args.recipe_file:
+        if not os.path.isfile(file):
+            print(f"ERROR: file {file} does not exist")
+            exit(1)
+
+        result = process_recipe(file)
+        results.append(result)
+
+        if not result and args.fail_fast:
+            exit(1)
+
+    if not all(results):
+        exit(1)
+    else:
+        exit(0)