Local-first Marp presentation editor: your decks stay plain, portable Markdown. Built-in privacy scan and redaction, TLP classification, 32 languages. No backend, no telemetry, open source. https://www.librekat.nl/
  • Dart 91.3%
  • JavaScript 8%
  • Makefile 0.3%
  • C++ 0.1%
  • Shell 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-02 08:44:40 +00:00
.forgejo docs(release): leg de manifest-handtekening en de verificatieroute vast (#1014) 2026-07-31 22:23:59 +02:00
.github docs(security): verversingstrigger dreigingsmodel in de PR-checklist (#1015) 2026-07-31 22:36:14 +02:00
android feat(iconen): één script snijdt alle zes de icoonsets uit één master 2026-07-23 19:16:58 +02:00
assets feat(templates): voeg invulhulp toe aan procesverbetering 2026-08-02 04:23:22 +02:00
assurance docs(design): bewaker-correcties — beloftefout, relay-reconciliatie, crypto-review 2026-08-02 00:46:38 +02:00
docs Merge pull request 'fix(privacy): dia-thumbnail-badge noemt de wérkelijke privacy-stand (#1112)' (#1115) from fix/privacy-badge-disposition-1112 into main 2026-08-02 08:44:40 +00:00
integration_test fix(privacy): herstel de gezichtsscan — dartcv4 2.x miste objdetect/dnn 2026-07-26 17:19:09 +02:00
ios feat(iconen): één script snijdt alle zes de icoonsets uit één master 2026-07-23 19:16:58 +02:00
lib Merge pull request 'fix(privacy): dia-thumbnail-badge noemt de wérkelijke privacy-stand (#1112)' (#1115) from fix/privacy-badge-disposition-1112 into main 2026-08-02 08:44:40 +00:00
linux feat(deps): migreer opencv_core -> dartcv4 2.x (native assets) 2026-07-26 15:04:00 +02:00
macos feat(deps): migreer opencv_core -> dartcv4 2.x (native assets) 2026-07-26 15:04:00 +02:00
sbom fix(multiwindow): schrap kInvalidArguments-melding bij opstart en presentatie 2026-08-01 23:46:58 +02:00
scripts feat(release): teken SHA256SUMS met een minisign detached signature (#1014) 2026-07-31 22:23:59 +02:00
semgrep feat(poort): make sast — Semgrep-regels over de uitgeleverde Dart 2026-07-22 00:48:01 +02:00
server/fetch-proxy docs(hosting): de fetch-proxy-eisen als harde release-voorwaarden 2026-07-22 03:56:52 +02:00
test Merge pull request 'fix(privacy): dia-thumbnail-badge noemt de wérkelijke privacy-stand (#1112)' (#1115) from fix/privacy-badge-disposition-1112 into main 2026-08-02 08:44:40 +00:00
third_party fix(multiwindow): schrap kInvalidArguments-melding bij opstart en presentatie 2026-08-01 23:46:58 +02:00
tool feat(managementsysteem): ISO 27001/9001/42001 index-catalogi (Blok A) 2026-08-02 05:32:20 +02:00
web fix(web): stop shipping doc-comments in web/index.html to every visitor 2026-07-29 10:31:47 +02:00
windows feat(deps): migreer opencv_core -> dartcv4 2.x (native assets) 2026-07-26 15:04:00 +02:00
zap security(web): lever de beveiligingsheaders mee als web/.htaccess (#849) 2026-07-25 12:23:13 +02:00
.gitattributes fix(windows): ref-paden portabel, LF-checkout, trash-skip (#880) 2026-07-26 12:00:28 +02:00
.gitignore chore(repo): verwijder gelekte transiënte cockpit-capture-test uit main 2026-08-01 13:58:33 +02:00
.gitleaks.toml fix(poort): sluit gits eigen boekhouding uit van de geheimenscan 2026-07-22 13:00:35 +02:00
.metadata Initial commit: OciDeck Marp presentation builder 2026-06-02 23:28:39 +02:00
.tool-versions chore(toolchain): pin Flutter 3.44.7 → 3.44.8 2026-07-27 14:21:52 +02:00
.trufflehogignore fix(poort): sluit gits eigen boekhouding uit van de geheimenscan 2026-07-22 13:00:35 +02:00
analysis_options.yaml Add quality-check tooling, an export-sanitisation test, and strict inference 2026-06-29 11:57:22 +02:00
AUDIT_RESPONSE.md docs(audit): de reactie op de beveiligings- en architectuuraudit 2026-07-22 04:51:21 +02:00
AUTHORS.md docs: add a contributors thank-you page (CONTRIBUTORS.md) 2026-07-28 01:40:13 +02:00
CHANGELOG.md Merge pull request 'fix(privacy): dia-thumbnail-badge noemt de wérkelijke privacy-stand (#1112)' (#1115) from fix/privacy-badge-disposition-1112 into main 2026-08-02 08:44:40 +00:00
CODE_OF_CONDUCT.md docs: één masthead per document, en de onderhoudsregels opgeschreven 2026-07-22 03:53:09 +02:00
COMPLIANCE.md fix(docs): de uitgever draait twee servers, niet één (#589) 2026-07-23 12:43:22 +02:00
CONTRIBUTING.md chore(toolchain): pin Flutter 3.44.7 → 3.44.8 2026-07-27 14:21:52 +02:00
CONTRIBUTORS.md docs: voeg Youetta de Jager toe als contributor 2026-08-02 03:22:55 +02:00
dart_test.yaml Add slide-renderer visual-regression goldens (make test-golden) 2026-06-30 11:09:58 +02:00
dco.txt docs(dco): neem de Developer Certificate of Origin aan (#594) 2026-07-23 00:53:29 +02:00
LICENSE.md chore: voeg jaartal 2026 toe aan copyrightregel 2026-07-09 12:29:59 +02:00
Makefile feat(release): teken SHA256SUMS met een minisign detached signature (#1014) 2026-07-31 22:23:59 +02:00
minisign.pub feat(release): teken SHA256SUMS met een minisign detached signature (#1014) 2026-07-31 22:23:59 +02:00
pubspec.lock feat(collab): CollabCrypto — pure-Dart E2EE seam met KAT-vectoren en mutatietoets (P-A) 2026-07-31 19:36:53 +02:00
pubspec.yaml feat(collab): CollabCrypto — pure-Dart E2EE seam met KAT-vectoren en mutatietoets (P-A) 2026-07-31 19:36:53 +02:00
README.md feat: voeg controle op afbeeldingsrechten toe 2026-08-02 01:07:25 +02:00
security-insights.yml docs: voeg security-insights.yml toe, met een poort erop 2026-07-22 18:12:18 +02:00
SECURITY.md docs(release): leg de manifest-handtekening en de verificatieroute vast (#1014) 2026-07-31 22:23:59 +02:00
SOURCE.md fix(release): bronaanwijzing erbij, machinegebonden bestand eruit (#520) 2026-07-22 20:09:03 +02:00
THIRD_PARTY_NOTICES.md docs(managementsysteem): benoem de fundament-asymmetrie (bewaker-bevinding) 2026-08-02 05:48:40 +02:00
trivy.yaml feat(ci): advisory Trivy supply-chain scan (Dart-CVE's + secrets) 2026-07-05 23:02:14 +02:00

OciDeck

Status: current-state project overview · Status last reviewed: 2026-07-22 · Published by: Stichting LibreKAT

Alpha — releases are now tagged (latest: 0.1.1, 2026-07-27). You can build from source, or download a release build; either way the file format is the part meant to be stable (FILE_FORMAT.md), while the application is not yet. What is missing, rough or untested is collected in KNOWN_LIMITATIONS.md.

A desktop and web application for building Marp-compatible presentations through a structured, slide-by-slide editor — no raw Markdown wrangling required. Compose decks from typed slide templates, preview them live, present them fullscreen across two screens, and export to Marp Markdown, PDF, PPTX and offline HTML.

Try it in your browser: https://ocideck.librekat.nl/ — the web build, running entirely in your own tab; nothing you type or open is uploaded. It is the smaller half of the two: no local video, no local CVE database, no WebDAV browsing, and a URL import that a browser blocks on CORS grounds is retried through a proxy on that host — which then sees the address you typed (the full list). For everything, build the desktop app — BUILD.md.

The OciDeck editor: the slide strip on the left, a per-type editor in the
middle, and a thumbnail preview — here a penetration-test report deck with a
finding slide open.

And because a deck is something you hand to other people, OciDeck reads it back to you before you do: it flags the personal data it can recognise, and — if you ask it to — removes that data from everything you show and export, while your Markdown keeps the original.

Built with Flutter for macOS, Windows, Linux, and web.

What's in a name? OciDeck is a small wink: Oci is borrowed from the Ocicats — the initiator's cats — and Deck is short for a presentation deck. So: the cats' presentation tool. (Who that is, and who publishes this, is in AUTHORS.md.)

Independent of Marp. OciDeck reads and writes Marp-compatible Markdown, but it is not affiliated with, endorsed by, or a product of the Marp Team, and it does not embed Marp Core. The renderer is its own, built on marked — see ARCHITECTURE.md. Compatibility with the Marp CLI is a design goal that has not yet been verified against the real tool.

Runs on your device, not on a server. No application backend for editing, no telemetry, no analytics, no phoning home; the privacy scan runs on your device too. Most outbound calls are ones you start and point where you choose, but four are not — the web CORS fetch-proxy, the CVE mirror, the local CVE database's bulk download, and an embedded YouTube or Vimeo player. All of them, with what each one sends, are listed in PRIVACY.md; the mechanics are in ARCHITECTURE.md. The demo above is the one place where the device is a page the publisher serves: the work still happens in your tab and no deck is uploaded, but the origin is ours — what that means.

What it does

  • Structured slide editors — a dedicated editor per slide type: title, bullets, images, quote, table, code, video, audio, and more.
  • Privacy check and redaction (OciWacht) — every slide is read for personal data, and what you mark is left out of display and export, not painted over.
  • Live preview and fullscreen presenter — presenter view, dual screens, a rehearsal clock, an annotation layer, and live table editing.
  • Charts, timelines and quiz slides — thirteen chart types from CSV or an in-app grid, animated timelines, and interactive question slides.
  • Cockpit dashboards — up to six aviation-style instruments, with an authentic panel look, a classic fallback and a staged power-on sequence in the presenter.
  • Traffic Light Protocol — deck-wide and per-slide classification, WYSIWYG marking, and optional export policy that fails closed.
  • Import and export — round-trips Marp Markdown, and exports to PDF, PPTX with speaker notes, and a self-contained offline HTML deck.
  • Storage — local project folders, a portable .ocideck package, Nextcloud/WebDAV, S3, or a git repository with history and releases.
  • Theming, 32 languages and accessibility — style profiles that travel as a file, a dark interface, and interface text scaling to 200%.

The full account of each — every slide type, every option, and the limits — is in the User Guide.

A few of those, seen rather than described:

Privacy scan (OciWacht) Export for a recipient
The quality panel showing two privacy findings; the matched value is shown truncated — "IP-adres (1…0)", "telefoonnummer (+…8)" — never in full, the same way the app treats it everywhere. The export dialog with the audience choice: Full for the client or auditor, Redacted for a wider circle.

The presenter view: the current slide, the next one, your notes and a rehearsal clock — on the screen the audience never sees.

A chart is data, not a picture The slide that grid renders
The chart editor: a grid of labels and numbers per series, with chart type, variants and CSV import above it — the slide draws itself from these values. A bar chart slide with three series per quarter, drawn in the deck's style profile with its logo.
A heatmap as a risk matrix A cockpit dashboard
A heatmap chart used as a probability-times-impact risk matrix: five classes each way, cells coloured from pale yellow to deep red with a colour scale below. An authentic cockpit slide with four instruments mounted in a dark panel: a speedometer, thermometer, voltmeter and climb/descent indicator, with bezels, screws, warning lamps and coloured operating ranges.
A timeline from a plain Markdown list A question slide, answered live
An animated timeline slide with four events from report to evaluation, each a labelled card on one line. A quiz slide with four answer options; the correct one is highlighted green after answering.
Classification that travels with the slide The same editor, dark
A slide marked TLP:AMBER: a corner label and an organization watermark over the content, both rendered by the app rather than pasted on. The editor in the dark interface profile, showing the same chart editor and slide strip.

(These are the desktop build. The web build in your browser runs the same renderer; a few things are desktop-only — video, the CVE lookup, the local CVE database.)

Specialist modules (off by default)

Hidden in the interface until you switch them on under Settings → Extensions, so they cost the ordinary user nothing.

  • Information-security reporting (MIAUW) — reports structured to the MIAUW methodology: finding, checklist, scope-matrix and sign-off slides, a CVSS 4.0 builder, an offline CWE picker, sealing and an encrypted audit dossier. All reference data ships with the app; nothing goes out. See the User Guide.
  • AI assistance — an optional local model or consented endpoint that drafts finding text and image alt-text. AI-drafted content is marked and blocks sealing until a human reviews it. See AI_ASSIST.md.
  • Image-rights check — locally flags repository images that may need a copyright or licence review, then stores the administrator's decision beside the shared asset. It is an indication, never a legal conclusion. See the User Guide.

Requirements

  • Flutter 3.44.8 (stable) — the pinned toolchain (see .tool-versions), bundling Dart 3.12.2. The pubspec.yaml Dart SDK constraint is ^3.12.0; building tolerates Flutter 3.44+, but make format-check is version-sensitive (see BUILD.md).
  • A desktop target enabled: macOS, Windows, or Linux — or run in a browser via Flutter web

Getting started

Download OciDeck for macOS, Windows, Linux or the web from the releases page. Every release carries the app for all four platforms, both SBOM formats and a SHA256SUMS to verify what you downloaded. The binaries are unsigned, so macOS and Windows will warn on first launch — the release notes explain how to open them on each platform.

Or build and run from source:

make setup      # flutter pub get
flutter run -d macos   # or -d windows / -d linux / -d chrome

Development

The Makefile is the entry point for all quality checks. Run make help for the full list.

make check        # format + analysis + conventions + method length + dead code + tests & coverage
make check-full   # check + licences + SBOM freshness + web hardening + dependency report
make format       # auto-format all Dart code
make analyze      # flutter analyze only
make test         # full test suite only

Targeted test groups speed up focused work:

Target Covers
make test-contracts Markdown generation/parsing, save-load round-trips, field migration
make test-preview Slide rendering, footers, TLP, inline Markdown, text styles
make test-export PDF/PPTX export and project file-save behavior
make test-state Providers, undo/redo, search/replace, settings, recovery
make test-services Image, caption, and description sidecar services
make test-presenter Fullscreen presenter navigation and keyboard shortcuts

Run make check before pushing — it is the same quality gate (format check, static analysis, full test suite) you would wire into CI. make check-full adds licence compliance (make licenses), the vendored-JS security check (make deps-check), and the SBOM freshness gate (make sbom-verify). For the full reference — every check, what it covers, and how it is enforced — see docs/CHECKS.md.

OciDeck ships a machine-readable Software Bill of Materials (CycloneDX 1.6 + SPDX 2.3) covering every component, as described in the EU Cyber Resilience Act. We are not a manufacturer under that regulation and are not obliged to; we do it because it is part of building software properly — see docs/SBOM.md.

Project layout

lib/
  models/     # Deck, Slide, Settings data models
  services/   # Markdown, export, file, image, caption, recovery, rasterizer
  state/      # Riverpod providers (deck, editor, settings, tabs, clipboard)
  widgets/    # UI: app shell, panels, dialogs, per-type editors, presenter
  l10n/       # AppLocalizations (32 languages)
  theme/      # App theming
  utils/      # Small shared helpers (clipboard table parsing, URL launching)

State is managed with Riverpod.

File format

Presentations are saved as standard, Marp-compatible Markdown (.md) with a defined project folder layout and an optional portable .ocideck package. Anything that isn't plain Marp is kept in side files so the .md stays pure and portable: image captions, the annotation layer (.ink.json), and linked chart data (data/*.csv). A style profile also travels on its own as a .ocideckstyle file (JSON, with any custom logo embedded). The full specification — front matter, per-slide markup, style profile, sidecars, and the package format — is documented in docs/FILE_FORMAT.md.

Documentation

Full documentation index: docs/README.md — the five reader paths (user, developer, host, auditor, assistive technology) start there, and it also indexes the design documents. The current-state documents:

Document What it covers
API documentation The internal APIs and seams a contributor works with to extend the app
Architecture How the code fits together (for contributors)
Audit response Point-by-point response to the external code audits, each verdict weighed against the code
Build & release Building from source and producing distributables
Changelog Notable changes (nothing is released yet)
Checks & CI Every automated check, what it covers, and how each is enforced
Compliance attestation Voluntary security attestation (ORC WG light-weight checklist), including the rows we cannot tick
Contributing Setup, the quality gate, and how to propose changes
Contributing guidelines The fuller contribution workflow: reporting issues, pull requests, and coding standards
Contributors A word of thanks to the people who have helped shape OciDeck
Development setup Setting up a development environment from scratch, step by step
FAQ Common questions about features, security, and privacy
File format The Marp Markdown, front matter, sidecars, the .ocideck package, and the .ocideckstyle style profile
Glossary OciDeck-specific terms and the acronyms that recur in the code and docs
Hosting Building and serving the web build safely — the desktop apps need no hosting
Keyboard shortcuts Editor and presenter shortcuts
Known limitations What this alpha does not do yet, in one place
Licence compliance Open-source policy and the make licenses check
Migration guide Moving between versions — no breaking changes between releases yet
Performance Performance characteristics and the hard limits enforced in code
Privacy What stays local, what leaves, and on whose action
SBOM The machine-readable Software Bill of Materials and its CRA mapping
Security design The security design principles and the concrete mechanisms that enforce them
Security policy How to report a vulnerability
Source availability The EUPL source indication shipped in the web build — where the source lives and how to build it
Source map An index of the files under lib/, grouped per directory
Third-party notices Bundled components and their licences, and the owners of the trademarks OciDeck names
Troubleshooting Fixes for common problems
Accessibility What is accessible, and — the longer half — what is not
User Guide Using the app: slide types, charts, presenting, exporting, theming, the privacy check and redaction, and the information-security (pentest) module

Design documents

The design rationale and chosen architecture, kept separate from the current-state documents above. All eleven are listed with their real status in docs/README.md — each carries its own status banner, and where a design disagrees with the code, the code wins. That list is maintained in one place so it cannot go stale in two.

Where this lives

Repository https://pawprint.vigilis.online/LibreKAT/Ocideck
Issues and pull requests the tracker there — registration is open to anyone
Security reports security@librekat.nl — see SECURITY.md

The forge has an Actions runner (since 2026-07-23). It runs the quality gate on a v* tag (.forgejo/workflows/ci.yml) — not per pull request, and on a Mac runner rather than the server, because the same gate took 46 minutes there against 2.5 minutes on the Mac. It runs make check-no-coverage: the whole test suite, without the coverage floors. So run make check locally before you push: it is very nearly the only thing standing between a change and main, and the only place the coverage floors run at all. The one exception is .forgejo/workflows/scans.yml (#778), which runs the secret and SAST scans on every pull request and push — seconds rather than minutes, and for a credential the moment it is found is not interchangeable. The Linux gate (.forgejo/workflows/linux-gate.yml) and the desktop bundles (linux-build.yml, macos-build.yml) run on demand. See docs/CHECKS.md.

A v* tag runs .forgejo/workflows/release.yml: web, macOS and Linux builds here, the Windows build on the GitHub mirror, and all of them published as one release with the SBOM and SHA256SUMS — see docs/BUILD.md. Apart from that Windows lane, the workflow files under .github/ are reference definitions; Forgejo reads .forgejo/workflows/ instead.

Contributing

Contributions are welcome! Please read CONTRIBUTING.md and our CODE_OF_CONDUCT.md. In short: make check must pass, new UI strings must be translated in all languages, and file-format changes must be reflected in docs/FILE_FORMAT.md. For security issues, see SECURITY.md.

About the 32 languages: the interface runs in Dutch, English, German, French, Italian, Spanish, Portuguese, Polish, Czech, Slovak, Slovenian, Croatian, Bulgarian, Romanian, Hungarian, Greek, Danish, Swedish, Finnish, Estonian, Latvian, Lithuanian, Maltese, Irish, Ukrainian, Turkish, Indonesian, Frisian, Swiss German, Latin, Papiamento, and Klingon. That is roughly 71,500 translations, and they were produced during AI-assisted development — 289 of the 314 commits touching lib/l10n/translations/ carry an AI co-author trailer. No native speaker has reviewed them word by word. Two tests fail the build: one if a string is missing in any language, and one — since #677 — if a "translation" is still the English sentence. Together they catch absence and the most visible form of neglect, not quality. Corrections for a single language are among the most useful contributions this project can receive.

The 32 languages are the interface. The documentation is English. Every bundled document — user guide, privacy, security and the rest of the curated in-app set — exists only in English, and the reader says so above any document you open in another language. The machinery for a translation is already there: drop docs/USER_GUIDE.de.md beside the original and the app picks it up. (Written down 2026-07-22, #626: a translated title on an untranslated document raises an expectation the project does not meet, and that asymmetry is sharper than plainly having no documentation in your language.) (Corrected 2026-07-31: this said "All 24 bundled documents … the lot"; the in-app reader now ships a curated subset of docs/ — the developer and design docs live in the repository — so a fixed count and "the lot" no longer fit.)

License

Copyright © 2026 Stichting LibreKAT.

OciDeck was initiated and conceived by Brenno de Winter and is developed as an open-source project.

OciDeck is licensed under the European Union Public Licence v. 1.2 (EUPL-1.2). You may use, study, share, and modify the software under the terms of that licence. The full text is in LICENSE.md; the official versions in all EU languages are available from the EUPL collection.

SPDX-License-Identifier: EUPL-1.2

Errata

Corrections to this page, kept here rather than in the running text so the paragraphs above read as statements. Inside docs/ the house rule is the opposite — a correction stays where the error was; see How these documents are maintained in docs/README.md.

  • 2026-07-21, network traffic. This page said "the only outbound calls are ones you start", and listed neither the web fetch-proxy nor the publisher-run CVE mirror. It now names all four calls you do not choose.
  • 2026-07-22, video embeds. Both YouTube and Vimeo were described as loading a player script. Since that date the YouTube embed loads none, and it never touches youtube.com.
  • 2026-07-21, translations. The localisation line said "every interface string is translated in all of them, enforced by tests", which was then untrue for about fifty editor labels reaching the layer indirectly. (Superseded 2026-07-22: those fifty are done. check_hardcoded_text now fails on every violation with no ceiling, and the 244 keys that travel indirectly are checked for translation coverage in test/app_localizations_test.dart. What remains is narrower and structural: a handful of interpolated Dutch strings built in services — a classification refusal names the level in the message — cannot be keyed on a literal and so cannot be looked up at all. Tracked in #576.)
  • 2026-07-22, feature list. The features section was 24 bullets of up to 1,300 characters each, and gave the optional MIAUW module the same weight as the editor itself. It is now eight lines plus a modules section, with the detail in the User Guide.