Skip to content

LingenicLLC/lingenic-compose-chisel-path

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

「‍」 Lingenic Compose Chisel-Path

Enables modeling historically accurate Latin letterforms. Subtractive mark-making primitives for stone carving, wood engraving, and inscriptional letterforms.

Overview

This crate provides primitive types for modeling subtractive mark-making — where the tool removes material rather than depositing it. Unlike brush-path (flexible, additive) or pen-path (rigid, additive), chisel-path models the physics of carving into stone, wood, or metal.

Primitives only — rendering and simulation are handled by higher-level crates.

Why Chisel-Path Matters

Roman capitals — the foundation of Latin typography — were created by a two-stage process:

  1. Brush: Letters painted on stone (giving thick/thin variation from brush angle)
  2. Chisel: Letters carved following the painted guides (adding precision, serifs, depth)

The serifs on Roman letters are not decorative — they are functional artifacts of how a stonemason cleanly terminates a chisel cut. The thick/thin contrast comes from the brush, but the crispness and characteristic serifs come from the chisel.

Most digital typefaces model only outlines. They miss the underlying physics that created those forms. Chisel-path captures why letters look the way they do.

The Mark-Making Hierarchy

mark-path (abstract)
├── additive-mark (deposits material)
│   ├── brush-path (flexible instrument)
│   └── pen-path (rigid instrument)
└── subtractive-mark (removes material)
    ├── chisel-path (stone, wood — this crate)
    └── engrave-path (metal, fine work — future)

Additive vs Subtractive

Aspect Brush/Pen (Additive) Chisel (Subtractive)
Process Deposits material Removes material
Medium Paper, silk, vellum Stone, wood, metal
Dimension 2D mark 3D cut with depth
Light Ink color Shadow reveals form
Serifs Stroke artifacts Termination technique
Dynamics Pressure, speed Depth, approach angle

Dependencies

Core Types

Chisel Tool

use chisel_path::{Chisel, ChiselProfile};

// Roman V-cut chisel (classic inscriptions)
let roman = Chisel::new()
    .profile(ChiselProfile::V { angle: 60 })
    .width(40);

// U-cut chisel (softer, more forgiving)
let soft = Chisel::new()
    .profile(ChiselProfile::U { radius: 20 })
    .width(50);

// Flat chisel (backgrounds, relief work)
let flat = Chisel::new()
    .profile(ChiselProfile::Flat)
    .width(80);

Chisel Profiles

Profile Description Use
V { angle } V-shaped cut Roman inscriptions, sharp shadows
U { radius } U-shaped (rounded) Softer look, easier to carve
Flat Flat bottom Relief backgrounds, cleaning

Cut Dynamics

Unlike brush dynamics (pressure), chisel dynamics describe the cut:

use chisel_path::{CutDynamics, ApproachAngle};

let dynamics = CutDynamics::new()
    .depth(30)                          // How deep into stone (centipoints)
    .approach_angle(ApproachAngle::Perpendicular)
    .with_grain(Direction::Along);      // Cutting with/against grain
Parameter Description
depth How deep the cut (affects shadow)
approach_angle Angle chisel enters stone
grain_direction Relation to material grain
material_hardness Affects what's achievable

Serif Cuts

Serifs are termination techniques — ways to cleanly end a chisel stroke:

use chisel_path::SerifCut;

// Classic Roman triangular serif
let roman_serif = SerifCut::Triangular {
    width: 60,
    depth: 25,
};

// Bracketed (smooth transition to stem)
let bracketed = SerifCut::Bracketed {
    width: 50,
    curve_radius: 15,
};

// Slab (Egyptian style)
let slab = SerifCut::Slab {
    width: 70,
    thickness: 20,
};

// No serif (modern, or where strokes meet)
let none = SerifCut::None;

Stone/Material Types

The substrate affects what cuts are possible:

use chisel_path::{Stone, StoneType, Grain};

// Marble — fine grain, allows delicate work
let marble = Stone::new(StoneType::Marble)
    .grain(Grain::Fine)
    .hardness(0.6);

// Limestone — coarser, faster to carve
let limestone = Stone::new(StoneType::Limestone)
    .grain(Grain::Medium)
    .hardness(0.4);

// Granite — very hard, requires different technique
let granite = Stone::new(StoneType::Granite)
    .grain(Grain::Coarse)
    .hardness(0.9);

// Wood (for woodcut/engraving)
let boxwood = Stone::new(StoneType::Wood)
    .grain(Grain::EndGrain)  // End-grain for fine detail
    .hardness(0.3);

Cut Segments

A cut is a path with chisel dynamics at each point:

use chisel_path::{CutSegment, CutPoint, Chisel};
use pen_path::{Point, Connector};

let segment = CutSegment {
    point: CutPoint {
        position: Point::new(100, 500),
        depth: 30,
        approach: ApproachAngle::Perpendicular,
    },
    connector: Connector::Line,
    action: CutAction::Continue,
};

Cut Actions

Actions describe what happens at each point:

Action Description
Entry Begin cut — chisel enters stone
Continue Continue cut at same depth
Deepen Increase depth
Shallow Decrease depth
CleanUp Finishing cut to clean edges
SerifCut(SerifCut) Execute serif termination
Exit End cut — chisel leaves stone

Complete Stroke

use chisel_path::{ChiselStroke, StrokeBuilder, Chisel, SerifCut};

let chisel = Chisel::v_cut(60).width(40);

let stroke = StrokeBuilder::new(chisel)
    // Entry with triangular serif
    .entry_serif(SerifCut::Triangular { width: 60, depth: 25 })
    .move_to(50, 0)
    .depth(30)
    // Main stem
    .cut_to(50, 700)
    // Exit with triangular serif
    .exit_serif(SerifCut::Triangular { width: 60, depth: 25 })
    .build();

Example: Roman Capital 'A'

use chisel_path::{Glyph, StrokeBuilder, Chisel, SerifCut, Stone};

let chisel = Chisel::v_cut(60).width(40);
let stone = Stone::marble();

let a = Glyph::new('A')
    .advance_width(700)
    .on_stone(stone)

    // Left diagonal stem
    .stroke(
        StrokeBuilder::new(chisel)
            .entry_serif(SerifCut::Triangular { width: 50, depth: 25 })
            .move_to(50, 0)
            .depth(30)
            .cut_to(350, 720)
            .exit_serif(SerifCut::None)  // Meets apex
            .build()
    )

    // Right diagonal stem
    .stroke(
        StrokeBuilder::new(chisel)
            .entry_serif(SerifCut::None)  // Meets apex
            .move_to(350, 720)
            .depth(30)
            .cut_to(650, 0)
            .exit_serif(SerifCut::Triangular { width: 50, depth: 25 })
            .build()
    )

    // Crossbar (shallower cut)
    .stroke(
        StrokeBuilder::new(chisel)
            .move_to(150, 280)
            .depth(20)  // Shallower than stems
            .cut_to(550, 280)
            .build()
    )

    .build();

Format Syntax

The .inscriptional format describes carved letterforms:

.stone-begin marble
  type Marble
  grain Fine
  hardness 0.6
.stone-end

.chisel-begin roman-v
  profile V
  angle 60
  width 40
.chisel-end

.glyph-begin A U+0041
  advance-width 700

  # Left stem
  .cut-begin roman-v
    serif-entry triangular 50 25
    depth 30
    cut-path 50,0 ⏤ 350,720
    serif-exit none
  .cut-end

  # Right stem
  .cut-begin roman-v
    serif-entry none
    depth 30
    cut-path 350,720 ⏤ 650,0
    serif-exit triangular 50 25
  .cut-end

  # Crossbar
  .cut-begin roman-v
    depth 20
    cut-path 150,280 ⏤ 550,280
  .cut-end

.glyph-end

Light and Shadow

Carved letters are designed to be read by shadow. The depth and angle of cuts determine how light falls:

use chisel_path::{LightSource, render_shadow};

let light = LightSource::new()
    .angle(45)      // 45° from top-left (classic)
    .intensity(1.0);

// Render produces shadow map showing how letter appears
let shadow_map = render_shadow(&glyph, &light);

Serif Taxonomy

Understanding serif types through their carving origin:

Serif Type Carving Technique Examples
Triangular Three cuts meeting at point Trajan, Times
Bracketed Curved transition cuts Garamond, Palatino
Slab Flat termination cuts Rockwell, Clarendon
Wedge Angled entry cut Optima (subtle)
None Clean stop (modern) Futura, Helvetica

Relief vs Incised

Two fundamental carving approaches:

use chisel_path::CarvingStyle;

// Incised: Letters cut INTO stone (most inscriptions)
let incised = CarvingStyle::Incised;

// Relief: Background cut away, letters RAISED
let relief = CarvingStyle::Relief {
    background_depth: 50,
};

Historical Accuracy

This crate enables modeling historically accurate Latin letterforms:

  • Roman Square Capitals (1st-2nd century) — Trajan's Column
  • Rustic Capitals — faster, more informal carving
  • Uncial — rounded forms, Christian inscriptions
  • Renaissance Inscriptional — Alberti, Palatino revival

Modules

  • chisel — Chisel tool definitions and profiles
  • stone — Stone/material properties
  • dynamics — Cut depth, angle, grain interaction
  • serif — Serif cut types and techniques
  • stroke — Cut segments and stroke building
  • light — Shadow rendering for carved forms
  • glyph — Complete glyph construction

License

Apache-2.0

Part of 「‍」 Lingenic Compose

Chisel-Path is a component of the 「‍」 Lingenic Compose typesetting system.

https://compose.lingenic.com

About

Subtractive mark-making primitives for stone and wood carving. Enables modeling historically accurate Latin letterforms.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages