diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..07fa008
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+**/*.pdf
+flake.lock
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e01bf94
--- /dev/null
+++ b/README.md
@@ -0,0 +1,51 @@
+# Clean Polylux Template
+
+This is a clean and dynamic presentation template for [Polylux](https://github.com/andreasKroepelin/polylux), a package for [Typst](https://typst.app/) to create nice looking presentations.
+
+Initial work was already done, but I added lots of neat features, so now this template features:
+- An easy to use templating interface, which just requires some meta information
+- A footer with arbitrary text and a slide counter
+- A slide counter, that does not suck! (as it only counts real slides and shows a total amount)
+- Dynamic logos on the title slide
+- Dynamic coloring via variables
+- Automatic creation of a contents slide
+- Dynamic header on each slide showing the slide's name and current section
+- Focus slides
+
+## Screenshots
+| Light Theme with Green Accent | Light Theme with Orange Accent | Dark Theme with Purple Accent |
+|:--:|:--:|:--:|
+|![light1](./screenshots/light1.png)|![light2](./screenshots/light2.png)|![dark1](./screenshots/dark1.png)|
+
+![titlepage](./screenshots/titlepage.png)
+
+![contents](./screenshots/contents.png)
+
+## How to use
+See [presentation.typ](./presentation.typ) for a sample presentation.
+Make sure you have `typst` installed, otherwise you could use the provided Nix Flake with `nix develop .`
+
+To just compile the presentation, run:
+```sh
+$ typst compile presentation.typ --open
+```
+
+To have a live preview, run:
+```sh
+$ typst watch presentation.typ --open
+```
+
+## Configure
+The entire templating part is done in [theme.typ](./theme.typ).
+Every major variable can be found towards the top of the file, marked with `CONFIG:` comments.
+Here you can configure the font and the color of the slides, the rest will be adjusted automatically.
+
+
+## Contribution
+Feel free to fork this repository and make adjustments as you wish, but I would appreciate a small notice somewhere.
+If you find visual bugs or have feature ideas, feel free to upstream them to this repository.
+
+## Inspirations
+- [matze/mtheme](https://github.com/matze/mtheme)
+- [Enive](https://github.com/Enivex)
+- [hargoniX](https://github.com/hargoniX/)
diff --git a/figures/ferris.png b/figures/ferris.png
new file mode 100644
index 0000000..d1e9f80
Binary files /dev/null and b/figures/ferris.png differ
diff --git a/figures/polylux.png b/figures/polylux.png
new file mode 100644
index 0000000..68bf2da
Binary files /dev/null and b/figures/polylux.png differ
diff --git a/figures/typst.svg b/figures/typst.svg
new file mode 100644
index 0000000..478d16c
--- /dev/null
+++ b/figures/typst.svg
@@ -0,0 +1,9 @@
+
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..a545f6b
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,35 @@
+{
+ description = "Nightly Typst with Typst LSP";
+
+ inputs.typst-lsp.url = "github:nvarner/typst-lsp";
+ inputs.typst.url = "github:typst/typst";
+ inputs.utils.url = "github:numtide/flake-utils";
+ inputs.nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
+
+ outputs = {
+ nixpkgs,
+ utils,
+ typst,
+ typst-lsp,
+ ...
+ }:
+ utils.lib.eachDefaultSystem (system: let
+ typst-overlay = _self: _super: {
+ typst-lsp = typst-lsp.packages.${system}.default;
+ typst = typst.packages.${system}.default.overrideAttrs (_old: {
+ dontCheck = true;
+ });
+ };
+ pkgs = nixpkgs.legacyPackages.${system}.appendOverlays [typst-overlay];
+ typst-shell = pkgs.mkShell {
+ nativeBuildInputs = [
+ pkgs.typst-lsp
+ pkgs.typst
+ ];
+ };
+ in {
+ devShells.default = typst-shell;
+ overlays.default = typst-overlay;
+ legacyPackages = pkgs;
+ });
+}
diff --git a/presentation.typ b/presentation.typ
new file mode 100644
index 0000000..cb9a7ba
--- /dev/null
+++ b/presentation.typ
@@ -0,0 +1,41 @@
+#import "theme.typ": *
+
+#show: presentation.with(
+ author: [Sample Author \],
+ title: [Sample Title],
+ occasion: [Sample Occasion],
+ date: [01.01.1970],
+ logos: ("figures/typst.svg", "figures/polylux.png", "figures/ferris.png"),
+ logo_height: 40%,
+ footer: [This is a really cool footer],
+)
+
+#section("My Section")
+#slide(title: "My Title")[
+ #grid(
+ columns: (50%, 50%),
+ [
+ - #lorem(10)
+ - #lorem(10)
+ - #lorem(10)
+ - #lorem(10)
+ ],
+ image("figures/ferris.png")
+ )
+]
+
+#focus-slide()[
+ We need to focus now...
+]
+
+#slide(title: "Some code!")[
+ #figure(
+ sourcecode(```rust
+ enum Foo {
+ Bar1(Box),
+ Bar2(String),
+ }
+ ```),
+ caption: [Some awesome Rust!]
+ )
+]
diff --git a/screenshots/contents.png b/screenshots/contents.png
new file mode 100644
index 0000000..d8b5111
Binary files /dev/null and b/screenshots/contents.png differ
diff --git a/screenshots/dark1.png b/screenshots/dark1.png
new file mode 100644
index 0000000..7913339
Binary files /dev/null and b/screenshots/dark1.png differ
diff --git a/screenshots/light1.png b/screenshots/light1.png
new file mode 100644
index 0000000..6d3bc83
Binary files /dev/null and b/screenshots/light1.png differ
diff --git a/screenshots/light2.png b/screenshots/light2.png
new file mode 100644
index 0000000..f460052
Binary files /dev/null and b/screenshots/light2.png differ
diff --git a/screenshots/titlepage.png b/screenshots/titlepage.png
new file mode 100644
index 0000000..a1b608c
Binary files /dev/null and b/screenshots/titlepage.png differ
diff --git a/theme.typ b/theme.typ
new file mode 100644
index 0000000..5eef6d9
--- /dev/null
+++ b/theme.typ
@@ -0,0 +1,191 @@
+#import "@preview/polylux:0.3.1": *
+#import "@preview/codelst:1.0.0": sourcecode
+
+// CONFIG: Font
+#let font = "Roboto"
+#let weight = "light"
+#let size = 20pt
+
+// CONFIG: Color
+#let color-primary = rgb("#66A182")
+#let color-foreground = rgb("#5c6a72")
+#let color-background = rgb("#ffffff")
+
+#let footer-lighten-value = 50% // how much lighter the color of the footer is
+#let section-foreground = color-background // color of text on section slide and headers
+#let focus-background = color-foreground // background of the focus slide
+#let focus-foreground = color-background // foreground of focus slide
+
+// Footer in the bottom left
+#let custom-footer = state("custom-footer", none)
+
+// Last section in the top left
+#let last-section = state("last-section", none)
+
+// A normal slide
+#let slide(title: none, is_toc: false, body) = {
+ let header-cell = block.with(
+ width: 100%,
+ height: 100%,
+ above: 0pt,
+ below: 0pt,
+ breakable: false
+ )
+
+ // Bar in the top
+ let header = {
+ set align(top)
+ if title != none {
+ show: header-cell.with(fill: color-primary, inset: 1.2em)
+ set align(horizon)
+
+ if not is_toc {
+ text(fill: section-foreground, size: 0.6em, last-section.display())
+ text([\ ])
+ }
+ text(fill: section-foreground, size: 1.2em, strong(title))
+
+ } else { [] }
+ }
+
+ // Footer with text on the left and slide count on the right
+ let footer = {
+ set text(size: 0.6em)
+ show: pad.with(1em)
+ set align(bottom)
+ let footer-color = color-foreground.lighten(footer-lighten-value)
+ text(fill: footer-color, custom-footer.display())
+ h(1fr)
+ text(fill: footer-color, [#logic.logical-slide.display()/#utils.last-slide-number])
+ }
+
+ set page(
+ header: header,
+ footer: if not is_toc { footer } else [],
+ margin: (top: 5em),
+ fill: color-background,
+ )
+
+ let content = {
+ show: align.with(horizon)
+ show: pad.with(left: 2em, right: 2em, top: -1.5em)
+ set text(fill: color-foreground)
+ body
+ }
+
+ logic.polylux-slide(content)
+
+ if is_toc {
+ // Don't count TOC slide towards slide count
+ logic.logical-slide.update(0)
+ }
+}
+
+
+// The actual presentation main
+#let presentation(
+ aspect-ratio: "16-9",
+ title: [Sample title],
+ occasion: [Sample occasion],
+ author: [Sample Author],
+ date: [01.01.1970],
+ logos: (),
+ logo_height: 50%,
+ footer: [],
+ body
+) = {
+ set text(font: font, weight: weight, size: size)
+ set strong(delta: 100)
+ set par(justify: true)
+
+ set page(
+ paper: "presentation-" + aspect-ratio,
+ fill: color-background,
+ margin: 0em,
+ header: none,
+ footer: none,
+ )
+
+ // save foother to global state
+ custom-footer.update(footer)
+
+ let title-slide = {
+ set text(fill: color-foreground, size)
+ set align(center + horizon)
+
+ block(width: 100%, inset: 2em, {
+ // Logo
+ if type(logos) == type("string") { // fix buggy behavior, with a single entry
+ align(center+horizon, image(logos, height: logo_height))
+ } else if logos.len() == 0 {
+ // Do not show any logos
+ } else {
+ grid(
+ columns: logos.len(),
+ ..logos.map((logo) => (align(center+horizon, image(logo, width: logo_height))))
+ )
+ }
+
+ text(size: 1.3em, strong(title))
+
+ line(length: 100%, stroke: .05em + color-primary)
+
+ set text(size: .8em)
+ h(1fr)
+ if author != none {
+ block(spacing: 1em, author)
+ }
+ if date != none {
+ block(spacing: 1em, date)
+ }
+ set text(size: .8em)
+
+ h(1fr)
+ if occasion != none {
+ set text(weight: "regular")
+ block(spacing: 1em, occasion)
+ }
+
+ })
+ }
+
+ logic.polylux-slide(title-slide)
+
+ // Show TOC
+ slide(title: "Contents", is_toc: true)[
+ #utils.polylux-outline(enum-args: (tight: false,))
+ ]
+
+ body
+}
+
+
+// Section brake slides with big title printed
+#let section(name) = {
+ set page(fill: color-primary)
+ let content = {
+ utils.register-section(name)
+ set align(horizon + center)
+ show: pad.with(20%)
+ set text(size: 2em, weight: "bold", fill: section-foreground)
+ name
+ }
+
+ logic.polylux-slide(content)
+
+ // Do not count section slides towards total slide count
+ logic.logical-slide.update(i => i - 1)
+
+ // Update last section name to display it in the following slides
+ last-section.update(name)
+}
+
+// Only show the text centered and big (good for a final slide)
+#let focus-slide(body) = {
+ set page(fill: focus-background, margin: 2em)
+ set text(fill: focus-foreground, size: 1.5em)
+ logic.polylux-slide(align(horizon + center, body))
+
+ // Do not count focus slides towards total slide count
+ logic.logical-slide.update(i => i - 1)
+}