Examples
Small documents, whole ideas.
Each example is a complete document. Run one in any host, change it, and save: the window follows.
Counter
Three buttons, three independent counters. State belongs to the call site, so each button keeps its own.
let button_colors = {
content: { r: 33, g: 30, b: 25, a: 255 },
border: { r: 134, g: 134, b: 145, a: 255 },
background: { r: 255, g: 255, b: 255, a: 170 },
};
let button = fn (label: String) {
state counter = 0;
Flex {
mouse_down: fn () {
counter = counter + 1;
},
style: {
width: 250,
height: 44,
direction: "row",
main_alignment: "start",
cross_alignment: "center",
background_color: button_colors.background,
border: {
width: 2,
color: button_colors.border,
style: "solid",
},
padding: { top: 10, right: 12, bottom: 10, left: 12 },
margin: { top: 6, right: 0, bottom: 6, left: 0 },
corner_radius: 10,
},
children: [
Text {
text: label + " " + counter,
style: {
width: "grow",
height: "shrink",
align: "left",
size: 18,
color: button_colors.content,
}
},
],
}
};
let main = fn () {
Flex {
style: {
width: "grow",
height: "grow",
main_alignment: "center",
cross_alignment: "center",
direction: "column",
padding: 24,
gap: 12,
background_color: {
r: 30,
g: 30,
b: 30,
a: 255,
},
},
children: [
button("Counter 1"),
button("Counter 2"),
button("Counter 3"),
],
}
};Conditional rendering
Widgets that come and go with state, using an if expression inside a children list.
let button_colors = {
content: { r: 33, g: 30, b: 25, a: 255 },
border: { r: 134, g: 134, b: 145, a: 255 },
background: { r: 255, g: 255, b: 255, a: 170 },
};
let counter_button = fn () {
state counter = 0;
Flex {
mouse_down: fn () {
counter = counter + 1;
},
style: {
width: 250,
height: 44,
direction: "row",
main_alignment: "start",
cross_alignment: "center",
background_color: button_colors.background,
border: {
width: 2,
color: button_colors.border,
style: "solid",
},
padding: { top: 10, right: 12, bottom: 10, left: 12 },
margin: { top: 6, right: 0, bottom: 6, left: 0 },
corner_radius: 10,
},
children: [
Text {
text: counter,
style: {
width: "grow",
height: "shrink",
align: "center",
size: 18,
color: button_colors.content,
}
},
],
}
};
let button = fn (label: String, on_click: function) {
Flex {
mouse_down: on_click,
style: {
width: 250,
height: 44,
direction: "row",
main_alignment: "start",
cross_alignment: "center",
background_color: button_colors.background,
border: {
width: 2,
color: button_colors.border,
style: "solid",
},
padding: { top: 10, right: 12, bottom: 10, left: 12 },
margin: { top: 6, right: 0, bottom: 6, left: 0 },
corner_radius: 10,
},
children: [
Text {
text: label,
style: {
width: "grow",
height: "shrink",
align: "left",
size: 18,
color: button_colors.content,
}
},
],
}
};
let main = fn () {
state counter_count = 0;
Flex {
style: {
width: "grow",
height: "grow",
main_alignment: "center",
cross_alignment: "center",
direction: "row",
padding: 24,
gap: 16,
background_color: {
r: 30,
g: 30,
b: 30,
a: 255,
},
},
children: [
Flex {
style: {
width: "grow",
height: "shrink",
direction: "column",
main_alignment: "center",
cross_alignment: "end",
gap: 12,
},
children: [
Text {
text: "Showing " + counter_count + " counters.",
style: {
size: 18,
color: { r: 255, g: 255, b: 255, a: 255 },
width: "grow",
align: "right",
},
},
button("Add counter", fn () {
counter_count = counter_count + 1;
}),
button("Remove counter", fn () {
if counter_count > 0 {
counter_count = counter_count - 1;
}
}),
],
},
Flex {
style: {
width: "grow",
height: "shrink",
direction: "column",
main_alignment: "start",
cross_alignment: "start",
gap: 4,
},
children: for (i in 0..counter_count) {
counter_button()
},
},
],
}
};Matching on state
The same idea with match. Passing callbacks as parameters keeps the button generic.
let button_colors = {
content: { r: 33, g: 30, b: 25, a: 255 },
border: { r: 134, g: 134, b: 145, a: 255 },
background: { r: 255, g: 255, b: 255, a: 170 },
};
let button = fn (label: String, on_click: function) {
Flex {
mouse_down: on_click,
style: {
width: 250,
height: 44,
direction: "row",
main_alignment: "start",
cross_alignment: "center",
background_color: button_colors.background,
border: {
width: 2,
color: button_colors.border,
style: "solid",
},
padding: { top: 10, right: 12, bottom: 10, left: 12 },
margin: { top: 6, right: 0, bottom: 6, left: 0 },
corner_radius: 10,
},
children: [
Text {
text: label,
style: {
width: "grow",
height: "shrink",
align: "left",
size: 18,
color: button_colors.content,
}
},
],
}
};
let main = fn () {
state view = "foo";
Flex {
style: {
width: "grow",
height: "grow",
main_alignment: "center",
cross_alignment: "center",
direction: "column",
padding: 24,
},
children: [
match view {
"foo" => {
button("Foo", fn () {
view = "bar";
})
},
"bar" => {
button("Bar", fn () {
view = "foo";
})
},
},
],
}
};Anchored tooltip
A Portal seated at a point the host computes. The renderer keeps it on screen, with no edge arithmetic in the document.
// Anchored portals: chrome seated at a point the HOST computes.
//
// A Portal that names an `anchor:` takes its viewport origin from
// the host's anchor map instead of from the slot it was declared
// in. Paint, hit-testing, occlusion and nesting all follow, because
// the anchor resolves into the same viewport-absolute rect an
// unanchored portal computes.
//
// The host side of this file is one line per frame:
//
// masque.set_anchor("cursor", Point::new(mouse_x, mouse_y));
//
// A previewer that does the same on every pointer move runs this
// file as-is: move the mouse and the card follows.
//
// Note what is NOT here: no edge arithmetic, no "am I near the
// bottom" branch, no measured card width. `anchor_policy` needs the
// subtree's laid-out size, which a document cannot see, so the renderer
// applies it after layout — that is the entire reason anchoring is
// a Portal property rather than a composition pattern.
let card = fn (title: String, body: String) {
Flex {
style: {
direction: "column",
width: 260,
padding: 10,
gap: 4,
background_color: { r: 22, g: 22, b: 26, a: 242 },
border: { width: 1, color: { r: 90, g: 90, b: 104, a: 255 } },
corner_radius: 6,
},
children: [
Text {
text: title,
style: { size: 15, color: { r: 236, g: 236, b: 242, a: 255 } },
},
Text {
text: body,
style: { size: 13, color: { r: 158, g: 158, b: 172, a: 255 } },
},
],
}
};
let main = fn () {
Flex {
style: {
width: "grow",
height: "grow",
direction: "column",
main_alignment: "center",
cross_alignment: "center",
gap: 8,
background_color: { r: 14, g: 14, b: 17, a: 255 },
},
children: [
Text {
text: "Move the pointer — the card follows it.",
style: { size: 16, color: { r: 222, g: 222, b: 230, a: 255 } },
},
Text {
text: "Near the bottom edge it flips above the pointer; near the right edge it pulls back inside.",
style: { size: 13, color: { r: 140, g: 140, b: 156, a: 255 } },
},
// The tooltip itself. `flip` reproduces the hand-rolled rule
// every Skia tooltip in every host has re-implemented:
// below-right of the pointer, above it when the card would
// overrun the bottom of the window, always inside the sides.
Portal {
layer: "tooltip",
open: true,
anchor: "cursor",
anchor_policy: "flip",
anchor_offset: { x: 14, y: 22 },
children: [
card("Anchored", "layer: tooltip · policy: flip · offset: 14, 22"),
],
},
// The same anchor, a different policy. `clamp` never flips —
// it only ever pulls the box back inside the 8 px inset — so
// side by side the two make the flip rule visible.
Portal {
layer: "toast",
open: true,
anchor: "cursor",
anchor_policy: "clamp",
anchor_offset: { x: 14, y: -96 },
children: [
card("Clamped", "same anchor, policy: clamp"),
],
},
],
}
};