<- Back to HomeThe principles and details of TypstFrontCore ArchitectureThe heart of TypstFront lies in its state-based architecture, drawing inspiration fromReact’s approach to managing user interfaces. At its core, the framework maintains aclear relationship between state and output: any given state will consistently producethe same rendered page. When users interact with the page through clicks orkeyboard inputs, these actions trigger state changes, which in turn cause theinterface to update accordingly.To overcome Typst’s inherent lack of interactive features, TypstFront employs acombination of HTML <a> tags, JavaScript event handlers, and client-servercommunication. This architecture enables interactive behavior while working withinTypst’s constraints.Example: Counter ImplementationConsider a simple counter implementation as an illustrative example:#import "../lib.typ": Button#let Page(ctx: (), query: (), storage: ()) = { let use-state = ctx.use-state let (counter, set-counter) = use-state("counter", 0) Button(set-counter(counter + 1))[Counter: #counter]}Let’s examine how a simple counter works:When a user first visits the page, the counter initializes to its default state of 0. Theframework then generates an <a> tag that displays "Counter: 0" as the currentstate. Crucially, this <a> tag’s href attribute contains the next potential state encodedas { counter: 1 }. This encoding represents the state transition that should occurwhen the user clicks the button.#let on-click(state, body) = { link("/_action?data=" + state-string(state))[#body]}On the frontend, JavaScript processes these special links in two steps. First, itremoves their href attributes to prevent default browser navigation. Then, it attachesclick event listeners to handle user interactions. When a user clicks the counterbutton, JavaScript sends a POST request to the server with the payload { counter:1 }, representing the desired new state.The backend receives the new state data. Then, it embeds this state into the Typstsource code. Next, it triggers a new render of the page. During this render, the use-state hook returns the updated value of 1, completing the state transition cycle.let state = {}if (req.method === "POST") { const data = await req.json(); state = data.state ?? {} // ...}Additional FeaturesBeyond this basic counter example, TypstFront implements additional featuresfollowing similar architectural principles. The framework includes storagemanagement through use-storage and keyboard event handling capabilities. Thesefeatures maintain the same pattern of state management and event processing, so iwon’t delve into them in detail here.LimitationsHowever, TypstFront does face several significant limitations. The framework’sarchitecture introduces notable latency since every interaction requires a completenetwork round-trip to the server for processing.The interaction model remains relatively basic, relying on manually bound JavaScriptevents rather than providing a rich set of native interactive capabilities.Furthermore, the current implementation lacks support for modern web featuressuch as animations and multimedia content, which can restrict its use in moredynamic web applications.At its heart, this project is just a fun experiment to explore the boundaries of Typst’s(or any other typesetting language’s) capabilities. The results might not be practical,but they’re certainly entertaining and might spark some interesting ideas for futureexperiments!