use blinc_app::prelude::*;
use blinc_app::windowed::{WindowedApp, WindowedContext};
use blinc_core::Color;
const STYLESHEET: &str = r#"
/* ====== Card 1: 3D Tilt ====== */
/* Perspective rotate-x/y following cursor — true 3D card effect */
#tilt-card {
pointer-space: self;
pointer-origin: center;
pointer-range: -1.0 1.0;
pointer-smoothing: 0.08;
border-radius: 16px;
background: #1e2438;
perspective: 800px;
rotate-y: calc(env(pointer-x) * env(pointer-inside) * 25deg);
rotate-x: -calc(env(pointer-y) * env(pointer-inside) * -25deg);
}
/* ====== Card 2: Hover Reveal ====== */
/* Fades from dim to full brightness on hover */
#reveal-card {
pointer-space: self;
pointer-origin: center;
pointer-range: -1.0 1.0;
pointer-smoothing: 0.12;
border-radius: 16px;
background: #2a1a3e;
opacity: calc(mix(0.3, 1.0, env(pointer-inside)));
}
/* ====== Card 3: Distance Fade ====== */
/* Opacity increases as pointer approaches center */
#distance-card {
pointer-space: self;
pointer-origin: center;
pointer-range: -1.0 1.0;
pointer-smoothing: 0.06;
border-radius: 16px;
background: #1a2e38;
opacity: calc(smoothstep(1.8, 0.0, env(pointer-distance)));
}
/* ====== Card 4: Dynamic Corners ====== */
/* Corner radius morphs continuously based on pointer proximity */
#corners-card {
pointer-space: self;
pointer-origin: center;
pointer-range: -1.0 1.0;
pointer-smoothing: 0.08;
border-radius: calc(mix(4, 48, smoothstep(1.4, 0.0, env(pointer-distance))) * 1px);
background: #1e3828;
opacity: calc(mix(0.4, 1.0, smoothstep(1.8, 0.0, env(pointer-distance))));
}
/* ====== Card 5: Border Glow ====== */
/* Border grows as pointer approaches center */
#border-card {
pointer-space: self;
pointer-origin: center;
pointer-range: -1.0 1.0;
pointer-smoothing: 0.06;
border-radius: 16px;
background: #1e2438;
border-width: calc(mix(0, 4, smoothstep(1.4, 0.0, env(pointer-distance))) * 1px);
border-color: #4488cc;
opacity: calc(mix(0.3, 1.0, smoothstep(1.8, 0.0, env(pointer-distance))));
}
/* ====== Card 6: Subtle Rotation ====== */
/* Card rotates gently following cursor x-position */
#rotate-card {
pointer-space: self;
pointer-origin: center;
pointer-range: -1.0 1.0;
pointer-smoothing: 0.1;
border-radius: 16px;
background: #382a1e;
rotate: calc(env(pointer-x) * env(pointer-inside) * 5deg);
opacity: calc(mix(0.5, 1.0, env(pointer-inside)));
}
/* ====== Card 7: Combined Effects ====== */
/* Multiple properties respond to cursor simultaneously */
#combo-card {
pointer-space: self;
pointer-origin: center;
pointer-range: -1.0 1.0;
pointer-smoothing: 0.08;
border-radius: calc(mix(8, 40, smoothstep(1.4, 0.0, env(pointer-distance))) * 1px);
background: #2a1a2e;
border-width: calc(mix(0, 3, smoothstep(1.2, 0.0, env(pointer-distance))) * 1px);
border-color: #cc66aa;
opacity: calc(smoothstep(1.6, 0.0, env(pointer-distance)));
rotate: calc(env(pointer-x) * env(pointer-inside) * 3deg);
}
"#;
fn main() -> Result<()> {
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::from_default_env()
.add_directive(tracing::Level::INFO.into()),
)
.init();
let config = WindowConfig {
title: "Pointer Query Demo".to_string(),
width: 1200,
height: 800,
resizable: true,
fullscreen: false,
..Default::default()
};
let mut css_loaded = false;
WindowedApp::run(config, move |ctx| {
if !css_loaded {
ctx.add_css(STYLESHEET);
css_loaded = true;
}
build_ui(ctx)
})
}
fn build_ui(ctx: &WindowedContext) -> impl ElementBuilder {
div()
.w(ctx.width)
.h(ctx.height)
.bg(Color::rgba(0.06, 0.06, 0.1, 1.0))
.flex_col()
.child(
div()
.w_full()
.flex_grow()
.flex_col()
.overflow_y_scroll()
.p(10.0)
.gap(20.0)
.child(
text("Pointer Query Demo")
.size(28.0)
.weight(FontWeight::Bold)
.color(Color::WHITE),
)
.child(
text("Move cursor over cards — all effects driven by CSS calc(env(pointer-*)) expressions")
.size(14.0)
.color(Color::rgba(0.6, 0.6, 0.7, 1.0)),
)
.child(
div()
.w_full()
.flex_col()
.gap(20.0)
.child(
div()
.w_full()
.flex_row()
.gap(20.0)
.child(card("tilt-card", "3D Tilt", "perspective + rotate-x/y follow cursor"))
.child(card("reveal-card", "Hover Reveal", "opacity: mix(0.3, 1.0, pointer-inside)"))
.child(card("distance-card", "Distance Fade", "opacity: smoothstep(1.8, 0, distance)")),
)
.child(
div()
.w_full()
.flex_row()
.gap(20.0)
.child(card("corners-card", "Dynamic Corners", "border-radius: mix(4, 48, smoothstep(distance))"))
.child(card("border-card", "Border Glow", "border-width: mix(0, 4, smoothstep(distance))"))
.child(card("rotate-card", "Subtle Rotation", "rotate: pointer-x * 5deg")),
)
.child(
div()
.w_full()
.flex_row()
.gap(20.0)
.child(card("combo-card", "Combined", "radius + border + opacity + rotate")),
),
),
)
}
fn card(id: &str, title: &str, description: &str) -> Div {
div()
.id(id)
.h(300.0)
.w(300.0)
.flex_col()
.p(20.0)
.gap(10.0)
.child(
text(title)
.size(20.0)
.weight(FontWeight::Bold)
.color(Color::WHITE),
)
.child(
text(description)
.size(13.0)
.color(Color::rgba(0.7, 0.8, 0.95, 1.0)),
)
.child(
text(format!("#{}", id))
.size(11.0)
.color(Color::rgba(0.4, 0.45, 0.55, 1.0)),
)
}