From Kyiv, in Kyiv.

  • 2 posts
  • 4 comments
Joined 5 months ago
Cake day: February 4th, 2026

I like the full-stack framework SvelteKit. It inspired me to write something more minimal, even brutalist, based on Preact, a few small focused modules popular in its ecosystem, and Vite.

There’s intentionally not much API. Documentation entirely fits in a long but straightforward README. Like the Django tutorial, it guides you through writing an application using all the primary features of the EviKit framework.

I wanted to use standard modern JavaScript as supported by Node.js 24+ directly. With strict JSDoc type annotations. So no separate language server is needed - you can use Emacs, Kate or any other modern editor of your choice that supports typescript-language-server. Linting using ESLint and Prettier also works without extra plugins.

There’s neither JSX nor a new templating language to learn. There are JS helpers for creating common elements, e.g. you write p({ class: "nav" }, a({ href: "/" }, "Home")). You use JS map for loops and ternary operator for conditional constructs.

I focused on old-school urlencoded and multipart forms, and the app is rendered on the server, so apps should remain partially accessible even when JS doesn’t load. At the same time, an EviKit app is a proper SPA, hydrated with client-side routing (with URLPattern-based server-side counterpart) and conveniently made dynamic with React-style hooks.

I want to ease the writing of bots and interoperability with low-code tools. So apps generate OpenAPI (Swagger) specification for your API.

Input/output validation using Valibot is first-class. Type checking catches if e.g. after an upgrade your API starts returning something different from your declaration. With less need for boilerplate unit tests, you can focus on end-to-end replication of real user scenarios.

Most apps need databases. Why not try the node:sqlite built-in? I made it easy to declare a schema using the same Valibot helpers that I use for API declaration. EviKit keeps the database in a standard location following the XDG specification. You can save file uploads as SQLite blobs.

Translatable strings of your UI can be automatically extracted using GNU Gettext tools, well-known in Django, WordPress and Linux desktop app ecosystems. I recomment the Poedit editor for translating the resulting .po files. Your app is shown in the browser language if there’s a matching translation, with English fallbacks.

For styling, I wanted to avoid non-standard hacks that make Node.js “import” CSS, so I recommend going with daisyUI and the now usual Tailwind CSS.

There’s a real-world FOSS app using EviKit: Lanquiz, that lets you import Kahoot quizzes and self-host them in LAN from a laptop during blackouts.

Non-goals: cloud deployment (I only target VPS and LAN apps), competition with Pracht scope (I guess there are bugs to fix, but the framework is more or less finished).

Last but not least, no “AI” whatsoever was used for writing the framework. I don’t have a hardline stance, it’s more that I don’t see how it could be useful for this tool. LLMs let people come up with ever mode code and boilerplate, while I want radically less of it. If you’d like to contribute, let’s keep it simple and human.

I like the full-stack framework SvelteKit. It inspired me to write something more minimal, even brutalist, based on Preact, a few small focused modules popular in its ecosystem, and Vite.

There’s intentionally not much API. Documentation entirely fits in a long but straightforward README. Like the Django tutorial, it guides you through writing an application using all the primary features of the EviKit framework.

I wanted to use standard modern JavaScript as supported by Node.js 24+ directly. With strict JSDoc type annotations. So no separate language server is needed - you can use Emacs, Kate or any other modern editor of your choice that supports typescript-language-server. Linting using ESLint and Prettier also works without extra plugins.

There’s neither JSX nor a new templating language to learn. There are JS helpers for creating common elements, e.g. you write p({ class: "nav" }, a({ href: "/" }, "Home")). You use JS map for loops and ternary operator for conditional constructs.

I focused on old-school urlencoded and multipart forms, and the app is rendered on the server, so apps should remain partially accessible even when JS doesn’t load. At the same time, an EviKit app is a proper SPA, hydrated with client-side routing (with URLPattern-based server-side counterpart) and conveniently made dynamic with React-style hooks.

I want to ease the writing of bots and interoperability with low-code tools. So apps generate OpenAPI (Swagger) specification for your API.

Input/output validation using Valibot is first-class. Type checking catches if e.g. after an upgrade your API starts returning something different from your declaration. With less need for boilerplate unit tests, you can focus on end-to-end replication of real user scenarios.

Most apps need databases. Why not try the node:sqlite built-in? I made it easy to declare a schema using the same Valibot helpers that I use for API declaration. EviKit keeps the database in a standard location following the XDG specification. You can save file uploads as SQLite blobs.

Translatable strings of your UI can be automatically extracted using GNU Gettext tools, well-known in Django, WordPress and Linux desktop app ecosystems. I recomment the Poedit editor for translating the resulting .po files. Your app is shown in the browser language if there’s a matching translation, with English fallbacks.

For styling, I wanted to avoid non-standard hacks that make Node.js “import” CSS, so I recommend going with daisyUI and the now usual Tailwind CSS.

There’s a real-world FOSS app using EviKit: Lanquiz, that lets you import Kahoot quizzes and self-host them in LAN from a laptop during blackouts.

Non-goals: cloud deployment (I only target VPS and LAN apps), competition with Pracht scope (I guess there are bugs to fix, but the framework is more or less finished).

Last but not least, no “AI” whatsoever was used for writing the framework. I don’t have a hardline stance, it’s more that I don’t see how it could be useful for this tool. LLMs let people come up with ever mode code and boilerplate, while I want radically less of it. If you’d like to contribute, let’s keep it simple and human.

  • I agree that incompatibility of most Android devices with free OS development is a huge problem, and that Android devices taking up an increasing share of all computers is a problem for FOSS rather than a benefit, despite the use of the Linux kernel. In shops around me, none of the phones affordable for someone with a 400 EUR / month salary will ever have LineageOS support, meaning that after two years they’ll all end up running abandoned, outdated, proprietary operating system forks, despite nothing technically preventing these capable computers from running a secure, up-to-date free OS for a few more years. This isn’t because of any issue on the LineageOS side, but because the entire Android device ecosystem is fixated on producing planned obsolescence and locking the user in.