Skip to main content

wisp_storybook/stories/
s_vector_render.rs

1//! Story: render vector primitives to scene geometry (M-VEC.2 / AUT-54).
2//!
3//! Five tiles showcasing the analytic shape variants of the
4//! `Vector` primitive — rect, rounded rect, circle, ellipse, plus a
5//! filled-with-stroke + opacity combo on the right. Path rendering
6//! is deferred to M-VEC.10.
7
8use glam::Vec2;
9use wisp::application::Application;
10use wisp::math::Rect;
11use wisp::{Color, Fill, Stage, Transform, Vector, VectorShape, VectorStroke};
12
13use crate::story::Story;
14
15pub fn story() -> Story {
16    Story {
17        id: "vector-render",
18        category: "Vector",
19        title: "Vector primitives",
20        milestone: "M-VEC.2 / AUT-54",
21        writeup: include_str!("writeups/vector_render.md"),
22        build,
23        tick: None,
24    }
25}
26
27fn build(_app: &Application, stage: &mut Stage) {
28    let root = stage.root();
29
30    // Tile positions across the canvas.
31    let xs = [-0.7_f32, -0.35, 0.0, 0.35, 0.7];
32    let scale = 0.14;
33    let bounds = Rect::new(-1.0, -1.0, 2.0, 2.0);
34
35    let entries = [
36        // Rect — solid teal fill.
37        Vector::new(VectorShape::rect(bounds))
38            .with_fill(Fill::Solid(Color::rgba_u8(80, 180, 200, 255)))
39            .with_transform(Transform {
40                position: Vec2::new(xs[0], 0.0),
41                scale: Vec2::splat(scale),
42                ..Transform::default()
43            }),
44        // Rounded rect — solid amber fill.
45        Vector::new(VectorShape::rounded_rect(bounds, 0.25))
46            .with_fill(Fill::Solid(Color::rgba_u8(220, 170, 80, 255)))
47            .with_transform(Transform {
48                position: Vec2::new(xs[1], 0.0),
49                scale: Vec2::splat(scale),
50                ..Transform::default()
51            }),
52        // Circle — gradient fill.
53        Vector::new(VectorShape::circle(Vec2::ZERO, 1.0))
54            .with_fill(Fill::LinearGradient {
55                start: Vec2::new(0.0, 1.0),
56                end: Vec2::new(0.0, -1.0),
57                color_a: Color::rgba_u8(220, 80, 130, 255),
58                color_b: Color::rgba_u8(120, 40, 200, 255),
59            })
60            .with_transform(Transform {
61                position: Vec2::new(xs[2], 0.0),
62                scale: Vec2::splat(scale),
63                ..Transform::default()
64            }),
65        // Ellipse — fill + stroke.
66        Vector::new(VectorShape::ellipse(Vec2::ZERO, Vec2::new(1.0, 0.55)))
67            .with_fill(Fill::Solid(Color::rgba_u8(120, 200, 130, 255)))
68            .with_stroke(VectorStroke::new(0.06, Color::WHITE))
69            .with_transform(Transform {
70                position: Vec2::new(xs[3], 0.0),
71                scale: Vec2::splat(scale),
72                ..Transform::default()
73            }),
74        // Rounded rect — half opacity, demonstrates fill+opacity.
75        Vector::new(VectorShape::rounded_rect(bounds, 0.4))
76            .with_fill(Fill::Solid(Color::rgba_u8(255, 255, 255, 255)))
77            .with_opacity(0.4)
78            .with_transform(Transform {
79                position: Vec2::new(xs[4], 0.0),
80                scale: Vec2::splat(scale),
81                ..Transform::default()
82            }),
83    ];
84
85    for entry in entries {
86        let _ = entry.add_to_stage(stage, root);
87    }
88}