diff --git a/.epub/example/META-INF/container.xml b/.epub/example/META-INF/container.xml
new file mode 100644
index 0000000..cb96e6f
--- /dev/null
+++ b/.epub/example/META-INF/container.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/.epub/example/OEBPS/content.opf b/.epub/example/OEBPS/content.opf
new file mode 100644
index 0000000..28cd01b
--- /dev/null
+++ b/.epub/example/OEBPS/content.opf
@@ -0,0 +1,25 @@
+
+
+
+ 2b982cb2-7144-4aa2-aa86-f9f6ba47fa0d
+ Unknown Title
+ Unknown Author
+ en
+ 2025-07-31T15:14:16Z
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.epub/example/OEBPS/images/.gitkeep b/.epub/example/OEBPS/images/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/.epub/example/OEBPS/sections/section0001.xhtml b/.epub/example/OEBPS/sections/section0001.xhtml
new file mode 100644
index 0000000..5db375c
--- /dev/null
+++ b/.epub/example/OEBPS/sections/section0001.xhtml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.epub/example/OEBPS/styles/stylesheet.css b/.epub/example/OEBPS/styles/stylesheet.css
new file mode 100644
index 0000000..df97adb
--- /dev/null
+++ b/.epub/example/OEBPS/styles/stylesheet.css
@@ -0,0 +1,49 @@
+.body {
+ -epub-writing-mode: horizontal-tb;
+ -webkit-writing-mode: horizontal-tb;
+ /* direction: ltr; */
+ direction: rtl;
+ writing-mode: horizontal-tb;
+
+ max-width: 100vw;
+}
+
+[data-ipub-element="page"] {
+ display: flex;
+ flex-direction: column;
+ position: relative;
+}
+
+[data-ipub-element="image"] {
+ width: var(--ipub-width, unset);
+ height: var(--ipub-width, unset);
+}
+
+[data-ipub-element="interaction"] {
+ position: absolute;
+ left: var(--ipub-x, 0%);
+ top: var(--ipub-y, 0%);
+ border-radius: var(--ipub-radius, unset);
+ width: var(--ipub-width, var(--ipub-size, unset));
+ height: var(--ipub-height, var(--ipub-size, unset));
+ transform: translate(
+ var(--ipub-origin-offset-x, 0%),
+ var(--ipub-origin-offset-y, 0%)
+ );
+ /*
+ * The opacity would be, by default, zero. Here it is 0.3 for easier debugging and
+ * showing of the example ebook
+ */
+ background-color: red;
+ opacity: 0.3;
+}
+
+a[data-ipub-element="interaction"] {
+ /* The text inside the interaction anchor are for accessibility purposes */
+ font-size: 0px;
+}
+
+img {
+ max-width: 100%;
+ max-height: 100%;
+}
diff --git a/.epub/example/OEBPS/toc.ncx b/.epub/example/OEBPS/toc.ncx
new file mode 100644
index 0000000..22bfa6b
--- /dev/null
+++ b/.epub/example/OEBPS/toc.ncx
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+ Section 1
+
+
+
+
+
+
diff --git a/.epub/example/OEBPS/toc.xhtml b/.epub/example/OEBPS/toc.xhtml
new file mode 100644
index 0000000..7b532d7
--- /dev/null
+++ b/.epub/example/OEBPS/toc.xhtml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/.epub/example/example.epub b/.epub/example/example.epub
new file mode 100644
index 0000000..7bceada
Binary files /dev/null and b/.epub/example/example.epub differ
diff --git a/.epub/example/mimetype b/.epub/example/mimetype
new file mode 100644
index 0000000..57ef03f
--- /dev/null
+++ b/.epub/example/mimetype
@@ -0,0 +1 @@
+application/epub+zip
\ No newline at end of file
diff --git a/flake.nix b/flake.nix
index 1803e5c..0ab8870 100644
--- a/flake.nix
+++ b/flake.nix
@@ -45,6 +45,12 @@
# S3
awscli
+
+ # ePUB
+ http-server
+ calibre
+ zip
+ unzip
];
};
});
diff --git a/makefile b/makefile
index 323e807..952586f 100644
--- a/makefile
+++ b/makefile
@@ -49,6 +49,19 @@ build: build/assets
run: build
./.dist/app
+epub/example:
+ cd ./.epub/example; zip ./example.epub ./META-INF/container.xml ./OEBPS/* ./OEBPS/**/* ./mimetype
+
+epub/example/server:
+ cd ./.epub/example; http-server
+
+calibre:
+ mkdir -p ./tmp/calibre-library
+ calibre \
+ --no-update-check \
+ --with-library=./tmp/calibre-library \
+ ./.epub/example/example.epub
+
clean:
# Remove generated directories
if [[ -d ".dist" ]]; then rm -r ./.dist; fi