This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
perfect-freehand is a TypeScript library for drawing pressure-sensitive freehand lines. It takes input points (from mouse/stylus) and generates polygon outline points that can be rendered as SVG paths or canvas shapes.
# Install dependencies (uses yarn workspaces)
yarn
# Start development server (runs both dev app and library watch)
yarn start
# Run all tests
yarn test
# Run tests in watch mode
yarn test:watch
# Run a single test file
yarn test packages/perfect-freehand/src/test/getStroke.spec.ts
# Run benchmarks
yarn bench
# Build the library
yarn build:packages
# Lint the library
cd packages/perfect-freehand && yarn lint
# Format code with Prettier
yarn format
# Check formatting without making changes
yarn format:check
# Generate API documentation
cd packages/perfect-freehand && yarn docsThis is a yarn workspaces monorepo with two packages:
packages/perfect-freehand/- The published npm librarypackages/dev/- Development/example React app (Vite, runs on port 5420)
The library has a simple pipeline architecture:
getStroke()- Main entry point. Combines the two functions below.getStrokePoints()- Converts raw input points[x, y, pressure?]intoStrokePoint[]objects with computed vectors, distances, and running lengths. Handles streamlining/smoothing.getStrokeOutlinePoints()- TakesStrokePoint[]and generates the final polygon outline points. Handles pressure simulation, tapering, caps, and sharp corner detection.
Supporting modules:
vec.ts- 2D vector math utilities (add, sub, mul, dist, per, etc.)getStrokeRadius.ts- Calculates radius based on pressure and thinningtypes.ts- TypeScript interfaces (StrokeOptions,StrokePoint)
The StrokeOptions interface controls stroke appearance:
size- Base diameter of strokethinning- How much pressure affects thickness (negative = thinner with pressure)smoothing- Edge softnessstreamline- Point interpolation amountsimulatePressure- Auto-calculate pressure from velocitystart/end- Tapering and cap options
- Library build: Rolldown (
packages/perfect-freehand/rolldown.config.mjs) - outputs dual CJS/ESM todist/ - Dev app: Vite with React plugin
- Task orchestration: lazyrepo (
lazy.config.js) - Testing: Vitest with jsdom environment
- Git hooks: Husky (pre-commit runs lint-staged, pre-push runs tests, commit-msg runs commitlint for conventional commits)