Introduction to Pax
Pax is a library for building web & native applications alongside visual creative tools
A quick tour
How it works
Pax is made up of two pieces:
- The interface declaration:
.pax
file - The application logic:
.rs
file
The interface declaration (or template for short) is a declarative way to specify the visual components of the user interface. Pax's templates can be created/edited via our design tool or by hand. See Designability to learn more about how it works.
Application logic is written in an accompanying Rust file (or Typescript, coming soon). This logic is triggered via handlers that are specified in templates and can set state that flows into templates.
Example
Writing Pax is intended to feel familiar, and the language borrows many ideas from prior art.
Following is a simple Pax component called IncrementMe
:
<Group x=50% y=50% width=120px height=120px @click=self.increment >
<Text text={self.num_clicks + " clicks"} id=text />
<Rectangle
fill={rgb(ticks, 75, 150)}
corner_radii={RectangleCornerRadii::radii(10.0,10.0,10.0,10.0)}
/>
</Group>
@settings {
@pre_render: handle_pre_render,
#text {
style: {
font: {Font::system("Times New Roman", FontStyle::Normal, FontWeight::Bold)},
font_size: 22px,
fill: WHITE,
align_vertical: TextAlignVertical::Center,
align_horizontal: TextAlignHorizontal::Center,
align_multiline: TextAlignHorizontal::Center
}
}
}
In this template we define a button that contains text and a rectangle. We use a group to combine them into an entity and attach a click handler to it. The text reads state self.num_clicks
and we set the fill (color) of the rectangles using self.ticks
as the red parameter of rgb(r,g,b)
. The last piece to note is the lifecycle handler we enabled in the settings block.
Based on this template our application logic must define the state of this component (num_clicks
, ticks
), the increment
function, and the handle_pre_render
function.
//File: lib.rs
#![allow(unused_imports)]
use pax_engine::api::*;
use pax_engine::*;
use pax_std::components::Stacker;
use pax_std::components::*;
use pax_std::primitives::*;
use pax_std::types::text::*;
use pax_std::types::*;
#[pax]
#[main]
#[file("lib.pax")]
pub struct Example {
pub ticks: Property<usize>,
pub num_clicks: Property<usize>,
}
impl Example {
pub fn handle_pre_render(&mut self, ctx: &NodeContext) {
let old_ticks = self.ticks.get();
self.ticks.set((old_ticks + 1) % 255);
}
pub fn increment(&mut self, ctx: &NodeContext, args: Event<Click>) {
let old_num_clicks = self.num_clicks.get();
self.num_clicks.set(old_num_clicks + 1);
}
}
In the accompanying rust file, we define the state struct and it's associated functions that we use in the template.
Here's the example component running:
The above IncrementMe
component could be mounted as its own app, or could be composed into other Pax components.
We will give a brief introduction to Pax: its goals, how to use it, and details of is design and implementation.