diff --git a/book.toml b/book.toml
index 9e1f042..8b11abd 100644
--- a/book.toml
+++ b/book.toml
@@ -7,6 +7,6 @@ title = "Lapwing for Beginners"
[output.html]
additional-css = ["theme/pagetoc.css"]
-additional-js = ["theme/pagetoc.js"]
+additional-js = ["theme/pagetoc.js", "theme/steno-viz.js"]
[preprocessor.external-links]
diff --git a/src/Chapter-01.md b/src/Chapter-01.md
index 5204b83..a2ebcde 100644
--- a/src/Chapter-01.md
+++ b/src/Chapter-01.md
@@ -25,7 +25,7 @@ This results in 10 successive key strokes. On the other hand, steno uses *chords
com/pli/cate
```
-![writing "complicate" with steno](img/1-complicate-steno.gif)
+
We could notate writing this word using steno like so:
diff --git a/src/img/steno-outline.svg b/src/img/steno-outline.svg
new file mode 100644
index 0000000..bdeed6c
--- /dev/null
+++ b/src/img/steno-outline.svg
@@ -0,0 +1,796 @@
+
+
diff --git a/theme/steno-viz.js b/theme/steno-viz.js
new file mode 100644
index 0000000..53c82ae
--- /dev/null
+++ b/theme/steno-viz.js
@@ -0,0 +1,167 @@
+function getThemeColors() {
+ const rootStyle = getComputedStyle(document.documentElement);
+
+ // Fetch specific color variables used by mdBook
+ const backgroundColor = rootStyle.getPropertyValue("--fg").trim();
+ const textColor = rootStyle.getPropertyValue("--bg").trim();
+
+ return { backgroundColor, textColor };
+}
+
+class SVGHelper {
+ constructor(svg) {
+ // Just create a document fragment to parse the SVG
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(svg, "image/svg+xml");
+ this.shadowRoot = doc;
+ this.shadowRoot.querySelectorAll(".pressed > path").forEach((element) => {
+ element.style.stroke = getThemeColors().backgroundColor;
+ });
+ this.shadowRoot
+ .querySelectorAll(".notpressed > path ")
+ .forEach((element) => {
+ element.style.stroke = getThemeColors().backgroundColor;
+ element.style.fill = getThemeColors().backgroundColor;
+ });
+ this.shadowRoot.querySelectorAll(".notpressed > g ").forEach((element) => {
+ element.style.stroke = getThemeColors().textColor;
+ element.style.fill = getThemeColors().textColor;
+ });
+ }
+ get string() {
+ const serializer = new XMLSerializer();
+ return serializer.serializeToString(this.shadowRoot);
+ }
+}
+
+class StenoViz extends HTMLElement {
+ static outline_regex =
+ /^(?#)?(?:(?S)?(?T)?(?K)?(?P)?(?W)?(?H)?(?R)?)?(?:(?A)?(?O)?)?(?\*)?(?:(?E)?(?U)?(?:-)?)?(?:(?F)?(?R)?(?