diff --git a/basic-example/README.md b/basic-example/README.md
new file mode 100644
index 0000000..9198eab
--- /dev/null
+++ b/basic-example/README.md
@@ -0,0 +1,15 @@
+# Grundlegendes Beispiel
+
+_FΓΌr Kapitel 3.3_
+
+[D3](https://d3js.org/) ist eine JavaScript-Bibliothek zur Datendarstellung.
+
+In `javascript.html` und `pyscript.html` wird dargestellt, wie Daten fΓΌr die Verwendung in D3 jeweils mit JavaScript und PyScript von einer externen Quelle in JSON-Form bezogen mithilfe von D3 in die Seite eingebettet werden.
+
+Die Darstellungen sollten exakt gleich aussehen.
+
+## Notizen/Hinweise
+
+`pyscript.py` in diesem Ordner wird nicht direkt verwendet, sondern ist nur eine Kopie des Skriptes aus `pyscript.js` und dient nur dem Zweck einer besser lesbaren Darstellung in gΓ€ngigen Editoren und auf GitHub.
+
+Der Kommentar `` verhindert, dass mein verwendeter Formatter Prettier den Inhalt `py-script`-Tags staucht und damit unbrauchbar macht.
diff --git a/basic-example/base.html b/basic-example/base.html
new file mode 100644
index 0000000..5a3dfdb
--- /dev/null
+++ b/basic-example/base.html
@@ -0,0 +1,179 @@
+
+
+ d3: JavaScript & PyScript visualizations side-by-side
+
+
+
+
+
+
+
+
+
+
+ Based on
+ Learn D3: Shapes
+ tutorial.
+
+
+
+
+
+
+
+
+
+ from pyodide import create_proxy, to_js
+ import d3
+
+ fruits = [
+ dict(name="π", count=21),
+ dict(name="π", count=13),
+ dict(name="π", count=8),
+ dict(name="π", count=5),
+ dict(name="π", count=3),
+ dict(name="π", count=2),
+ dict(name="π", count=1),
+ dict(name="π", count=1),
+ ]
+
+ fn = create_proxy(lambda d, *_: d["count"])
+ data = d3.pie().value(fn)(to_js(fruits))
+
+ arc = (d3.arc()
+ .innerRadius(210)
+ .outerRadius(310)
+ .padRadius(300)
+ .padAngle(2 / 300)
+ .cornerRadius(8))
+
+ py = d3.select("#py")
+ py.select(".loading").remove()
+
+ svg = (py
+ .append("svg")
+ .attr("viewBox", "-320 -320 640 640")
+ .attr("width", "400")
+ .attr("height", "400"))
+
+ for d in data:
+ d_py = d.to_py()
+
+ (svg.append("path")
+ .style("fill", "steelblue")
+ .attr("d", arc(d)))
+
+ text = (svg.append("text")
+ .style("fill", "white")
+ .attr("transform", f"translate({arc.centroid(d).join(',')})")
+ .attr("text-anchor", "middle"))
+
+ (text.append("tspan")
+ .style("font-size", "24")
+ .attr("x", "0")
+ .text(d_py["data"]["name"]))
+
+ (text.append("tspan")
+ .style("font-size", "18")
+ .attr("x", "0")
+ .attr("dy", "1.3em")
+ .text(d_py["value"]))
+
+
+
diff --git a/basic-example/javascript.html b/basic-example/javascript.html
new file mode 100644
index 0000000..14eae32
--- /dev/null
+++ b/basic-example/javascript.html
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+ D3 mit JavaScript
+
+
+
+
+
+
+
diff --git a/basic-example/pyscript.html b/basic-example/pyscript.html
new file mode 100644
index 0000000..174b092
--- /dev/null
+++ b/basic-example/pyscript.html
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+ D3 mit PyScript
+
+
+
+
+
+
+
+
+ from pyodide import create_proxy, to_js, open_url
+ import d3
+ import json
+
+ url = f"https://duolingo.checksch.de/duo_user_info.json"
+ res = open_url(url)
+ lang_info = json.loads(res.read())["lang_data"]
+ lang_info_prepped = []
+
+ for lang in lang_info:
+ item = dict(name=lang_info[lang]["learningLanguage"], count=lang_info[lang]["xp"])
+
+ if lang_info[lang]["xp"] > 500:
+ lang_info_prepped.append(item)
+
+ fn = create_proxy(lambda d, *_: d["count"])
+ data = d3.pie().value(fn)(to_js(lang_info_prepped))
+
+ arc = (
+ d3.arc()
+ .innerRadius(210)
+ .outerRadius(310)
+ .padRadius(300)
+ .padAngle(2 / 300)
+ .cornerRadius(8)
+ )
+
+ py = d3.select("#py")
+ py.select(".loading").remove()
+
+ svg = (
+ py.append("svg")
+ .attr("viewBox", "-320 -320 640 640")
+ .attr("width", "400")
+ .attr("height", "400")
+ )
+
+ for d in data:
+ d_py = d.to_py()
+
+ (svg.append("path").style("fill", "rebeccapurple").attr("d", arc(d)))
+
+ text = (
+ svg.append("text")
+ .style("fill", "white")
+ .attr("transform", f"translate({arc.centroid(d).join(',')})")
+ .attr("text-anchor", "middle")
+ )
+
+ (
+ text.append("tspan")
+ .style("font-size", "24")
+ .attr("x", "0")
+ .text(d_py["data"]["name"])
+ )
+
+ (
+ text.append("tspan")
+ .style("font-size", "18")
+ .attr("x", "0")
+ .attr("dy", "1.3em")
+ .text(d_py["value"])
+ )
+
+
+
diff --git a/basic-example/pyscript.py b/basic-example/pyscript.py
new file mode 100644
index 0000000..42ce7ac
--- /dev/null
+++ b/basic-example/pyscript.py
@@ -0,0 +1,63 @@
+from pyodide import create_proxy, to_js, open_url
+import d3
+import json
+
+url = f"https://duolingo.checksch.de/duo_user_info.json"
+res = open_url(url)
+lang_info = json.loads(res.read())["lang_data"]
+lang_info_prepped = []
+
+for lang in lang_info:
+ item = dict(name=lang_info[lang]["learningLanguage"], count=lang_info[lang]["xp"])
+
+ if lang_info[lang]["xp"] > 500:
+ lang_info_prepped.append(item)
+
+fn = create_proxy(lambda d, *_: d["count"])
+data = d3.pie().value(fn)(to_js(lang_info_prepped))
+
+arc = (
+ d3.arc()
+ .innerRadius(210)
+ .outerRadius(310)
+ .padRadius(300)
+ .padAngle(2 / 300)
+ .cornerRadius(8)
+)
+
+py = d3.select("#py")
+py.select(".loading").remove()
+
+svg = (
+ py.append("svg")
+ .attr("viewBox", "-320 -320 640 640")
+ .attr("width", "400")
+ .attr("height", "400")
+)
+
+for d in data:
+ d_py = d.to_py()
+
+ (svg.append("path").style("fill", "rebeccapurple").attr("d", arc(d)))
+
+ text = (
+ svg.append("text")
+ .style("fill", "white")
+ .attr("transform", f"translate({arc.centroid(d).join(',')})")
+ .attr("text-anchor", "middle")
+ )
+
+ (
+ text.append("tspan")
+ .style("font-size", "24")
+ .attr("x", "0")
+ .text(d_py["data"]["name"])
+ )
+
+ (
+ text.append("tspan")
+ .style("font-size", "18")
+ .attr("x", "0")
+ .attr("dy", "1.3em")
+ .text(d_py["value"])
+ )