Introduction
Ludic is a lightweight framework for building HTML pages with a component approach similar to React. It is built to be used together with htmx.org so that developers don't need to write almost any JavaScript to create dynamic web services. Its potential can be leveraged together with its web framework which is a wrapper around the powerful Starlette framework. It is built with the latest Python 3.12 features heavily incorporating typing.
Experimental The framework is in a very early development/experimental stage. There are a lot of half-functioning features at the moment. Contributions are welcome to help out with the progress!
Seamless </> htmx integration for rapid web development in pure Python
integration for rapid web development in Type-Guided components utilizing Python's typing system
utilizing Python's typing system Uses the power of Starlette and Async for high-performance web development
and for high-performance web development Build HTML with the ease and power of Python f-strings
Add CSS styling to your components with Themes
Create simple, responsive layouts adopted from the Every Layout Book
Here is a table comparing Ludic to other similar tools:
(*) HTMX as well as Starlette are optional dependencies for Ludic, it does not enforce any frontend or backend frameworks. At it's core, Ludic only generates HTML and allows registering CSS.
Quick Example #
Here is a simple re-implementation of an example from Reflex:
Decrement 0 Increment
The counter can be included on any page like here:
from typing import override from ludic.html import b from ludic.web import Endpoint, LudicApp, Request from ludic.catalog.buttons import ButtonDanger, ButtonSuccess from ludic.catalog.layouts import Box, Cluster app = LudicApp() @app . get( "/" ) def index (request: Request) -> Box: return Box(Counter( "0" ))
Note that the Box is just a component wrapping the buttons and the number to make it nicely framed. You can read more about the Box in the Layouts section later. Anyway, the Counter component is the part that is more interesting:
@app . get( "/counter/ {value} " ) def Counter (value: str ) -> Cluster: return Cluster( ButtonDanger( "Decrement" , hx_get = app . url_path_for( "Counter" , value = int (value) - 1 ), hx_target = "#counter" , ), b(value, style = { "font-size" : "2em" }), ButtonSuccess( "Increment" , hx_get = app . url_path_for( "Counter" , value = int (value) + 1 ), hx_target = "#counter" , ), id = "counter" , )
Python 3.12+
pip install "ludic[full]"
As similar for Starlette, you'll also want to install an ASGI server:
pip install uvicorn
You can also use the cookiecutter template to quickly create a new project:
cookiecutter gh:paveldedik/ludic-template
Any contributions to the framework are warmly welcome! Your help will make it a better resource for the community. If you're ready to contribute, read the contribution guide on GitHub.