Universal brush mark-making primitives, using Chinese calligraphic terminology.
This crate provides primitive types for modeling brush-based mark-making. Unlike pen-based strokes which sweep a rigid shape along a path, brush work involves a flexible instrument with evolving state.
Primitives only — rendering and simulation are handled by higher-level crates.
The primitives in this crate are universal, not CJK-specific. Chinese calligraphy has 2000+ years of formalized vocabulary for brush technique — these terms describe universal physics that applies to any brush-based art:
| Chinese | Keyword | Universal application |
|---|---|---|
| 頓 (dùn) | press-pause |
Loading a stroke (watercolor, oil) |
| 提 (tí) | lift |
Flicking out, feathering |
| 藏鋒 | hidden-tip |
Concealed stroke start |
| 中鋒 | center |
"Pulling" a stroke |
| 側鋒 | side-left/right |
"Dragging" the brush |
A watercolorist pressing the brush to spread pigment is doing 頓 — they just don't have a name for it.
What's universal:
Brush,BrushState— physical instrument and its evolutionDynamics— pressure, velocity, angle (輕重 light-heavy)BrushAction— press-pause, lift, sharp-turn, round-turn, twist (named in Chinese, universal behaviors)EntryStyle,ExitStyle,TipMode— stroke semanticsConnectionStyle— how marks connectInk,Paper— medium and surface properties
What's CJK-specific:
StrokeKind— the 橫豎撇捺 stroke classification (useOtherfor non-CJK)
This crate can model Chinese calligraphy, Japanese sumi-e, Western watercolor, or any brush-based technique.
- Lingenic Pen-Path — Point, Connector, and other geometry primitives
| Type | Description |
|---|---|
Brush |
Physical brush (tip/belly width, flexibility, bristle type) |
BrushState |
Evolving state (ink load, bend, spread) |
Dynamics |
Pressure (輕重 light-heavy), velocity, angle at a point |
BrushPoint |
Position + dynamics |
BrushSegment |
Point + connector + action |
BrushAction |
Brush behaviors (頓 press-pause, 提 lift, 折 sharp-turn, etc.) |
StrokeKind |
Stroke classification (橫, 豎, 撇, 捺, 點, etc.) |
StrokeSemantics |
Entry, exit, tip mode, connection |
ConnectionStyle |
How stroke connects to next (independent, flowing, 牽絲) |
Ink |
Ink properties (concentration, flow rate) |
Paper |
Paper properties (absorption, sizing) — source aesthetic |
BrushStroke |
Complete stroke definition |
Every stroke has a classification from the traditional CJK stroke taxonomy:
Basic strokes (基本筆畫):
| Kind | Chinese | Description |
|---|---|---|
Heng |
橫 | Horizontal |
Shu |
豎 | Vertical |
Pie |
撇 | Left-falling |
Na |
捺 | Right-falling |
Dian |
點 | Dot |
Ti |
提 | Rising |
Compound strokes (複合筆畫):
| Kind | Chinese | Description |
|---|---|---|
HengZhe |
橫折 | Horizontal-turn |
ShuGou |
豎鉤 | Vertical-hook |
HengZheGou |
橫折鉤 | Horizontal-turn-hook |
| ... | ... | ... |
The stroke kind automatically sets appropriate default entry/exit semantics.
In regular script (楷書), strokes are independent units. In running script (行書) and grass script (草書), strokes connect:
| Style | Chinese | Description |
|---|---|---|
Independent |
— | Stroke ends separately (楷書 default) |
Flowing |
— | Visual flow continues to next stroke (行書) |
SilkThread |
牽絲 | Visible thin linking line (草書) |
Airborne |
— | Brush lifts but momentum carries to next |
use brush_path::{StrokeSemantics, ConnectionStyle};
// Regular script (楷書): strokes are independent
let kaishu = StrokeSemantics::formal();
assert!(!kaishu.connection.connects());
// Running script (行書): strokes flow together
let xingshu = StrokeSemantics::running();
assert!(xingshu.connection.connects());
// Grass script (草書): visible silk threads connect strokes
let caoshu = StrokeSemantics::grass();
assert!(caoshu.connection.is_visible());Connectors (from pen-path) describe path geometry:
Line(⏤) — straight segmentCurve(⌒) — smooth curveCorner(∠) — sharp angle
Actions (提按) describe brush behavior:
PressPause(頓) — press down and pauseLift(提) — quick liftSharpTurn(折) — sharp angular turnRoundTurn(轉) — smooth pivotTwist(挫) — rotate handleSettleDown(蹲) — settle brush downQuickEntry(搶) — quick entry stroke
These are orthogonal. A segment can be Curve + PressPause (curved path with a press-pause at the point).
Ink and Paper describe the source aesthetic, not the output medium.
A Chinese calligraphy font designed for raw Xuan paper (生宣) carries that aesthetic — soft edges, bleeding, pooling. When rendered onto glossy card stock, the renderer reproduces those characteristics on the different medium.
// This describes the intended look, not where it prints
let paper = Paper::raw_xuan(); // absorbent, bleeds
let ink = Ink::thick(); // concentrated, slow-flowinguse brush_path::{
Brush, BristleType, StrokeBuilder, StrokeKind, TipMode,
};
let brush = Brush::new()
.tip_width(8)
.belly_width(40)
.flexibility(0.7)
.bristle(BristleType::Goat);
// StrokeKind sets default entry/exit semantics
let stroke = StrokeBuilder::new(brush, StrokeKind::HengZheGou) // 橫折鉤
.curve_to(100, 800)
.press_pause(300, 750) // 頓 press-pause
.curve_to(500, 700)
.sharp_turn(500, 400) // 折 sharp-turn
.curve_to(300, 200)
.lift(100, 100) // 提 lift (hook exit)
.tip_mode(TipMode::Center)
.ink_start(1.0)
.build();
assert_eq!(stroke.kind, StrokeKind::HengZheGou);
assert_eq!(stroke.kind.chinese_name(), "橫折鉤");brush— Brush definition, bristle typesstate— Evolving brush statedynamics— Pressure (輕重), velocity, angleaction— Brush behaviors (頓, 提, 折, etc.)stroke_kind— Stroke classification (橫, 豎, 撇, etc.)semantics— Entry (入鋒), exit (收鋒), tip mode (鋒法), connection (筆勢)ink— Ink propertiespaper— Paper propertiesstroke— BrushSegment, BrushStroke, StrokeBuildercontact— Contact shape computation
Apache-2.0
Brush-Path is a component of the 「」 Lingenic Compose typesetting system.