Components
The atomic unit of Pax is a component definition
. A component definition for MyNewComponent
may look like:
//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);
}
}
<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
}
}
}
You can think of the component definition as a package for a number of different interconnected pieces.
Inside a component definition, there may be:
A component definition centers around a Rust struct, to which a piece of Pax is attached to through the macro #[pax]
. Pax can either be attached inline using the inlined()
attribute or link to a .pax
file using the file()
attribute using a relative path. For example, the following defines an empty component called EmptyComponent
:
use pax_lang::api::*;
use pax_std::primitives::Group;
#[pax]
#[inlined(<Group />)] //a one-element template, simply an empty Group
pub struct EmptyComponent {
//no properties
}
Any component created in Pax can be used inside other components — for example, EmptyComponent
can be imported and used in another component's template like:
use pax_lang::api::*;
use crate::EmptyComponent;
#[pax]
#[inlined(<EmptyComponent />)] //another one-element template, ultimately still not rendering anything
pub struct StillEmptyComponent {
//no properties
}
This "components all the way down" pattern may be familiar if you have used a GUI framework like React or Vue.
This is essentially how you define a Pax Component. The only exception is the root component which is signified with the main
attribute and lives in the root lib.rs
.
Notice that Pax builds off of Rust's import and namespace resolution mechanisms, so importing crate::EmptyComponent
to a .rs
file means that you can use <EmptyComponent />
inside a template in that file.
You can read more about Pax components in the chapter Hardware Component Model.

A biological cell with computer chips for organelles