309 lines
8.2 KiB
Markdown
309 lines
8.2 KiB
Markdown
|
|
# CLAUDE.md
|
|||
|
|
|
|||
|
|
This file provides guidance to Claude Code when working with this repository.
|
|||
|
|
|
|||
|
|
## Project Overview
|
|||
|
|
|
|||
|
|
**pastel-wasm** is a WebAssembly color manipulation library built with Rust. It provides comprehensive color operations directly in the browser with zero network latency.
|
|||
|
|
|
|||
|
|
**Key Stats:**
|
|||
|
|
- Bundle size: 132KB (WASM)
|
|||
|
|
- Language: Rust + WebAssembly
|
|||
|
|
- Target: Modern browsers with WASM support
|
|||
|
|
- Dependencies: Minimal (wasm-bindgen, serde, rand, getrandom)
|
|||
|
|
|
|||
|
|
## Architecture
|
|||
|
|
|
|||
|
|
### Project Structure
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
pastel-wasm/
|
|||
|
|
├── src/
|
|||
|
|
│ ├── lib.rs # Main WASM bindings and exported functions
|
|||
|
|
│ ├── color.rs # Core color type and conversions
|
|||
|
|
│ └── named.rs # Named colors database (148 CSS/X11 colors)
|
|||
|
|
├── pkg/ # Build output (generated by wasm-pack)
|
|||
|
|
│ ├── pastel_wasm.js
|
|||
|
|
│ ├── pastel_wasm.d.ts
|
|||
|
|
│ └── pastel_wasm_bg.wasm
|
|||
|
|
├── Cargo.toml # Rust dependencies and configuration
|
|||
|
|
├── package.json # NPM package configuration
|
|||
|
|
├── README.md # User documentation
|
|||
|
|
└── example.html # Interactive demo
|
|||
|
|
|
|||
|
|
## Color Implementation
|
|||
|
|
|
|||
|
|
### Color Type (`src/color.rs`)
|
|||
|
|
|
|||
|
|
The core `Color` struct represents colors in RGB space (0.0-1.0 range):
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
pub struct Color {
|
|||
|
|
pub r: f64,
|
|||
|
|
pub g: f64,
|
|||
|
|
pub b: f64,
|
|||
|
|
pub a: f64,
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Key Methods:**
|
|||
|
|
- `parse(s: &str)` - Universal color parser (hex, rgb, hsl, named)
|
|||
|
|
- `to_hex()` - Convert to hex string
|
|||
|
|
- `to_hsl()`, `to_hsv()`, `to_lab()`, `to_lch()` - Color space conversions
|
|||
|
|
- `lighten()`, `darken()`, `saturate()`, `desaturate()` - Adjustments
|
|||
|
|
- `rotate_hue()`, `complement()`, `mix()` - Transformations
|
|||
|
|
- `text_color()`, `contrast_ratio()` - Accessibility helpers
|
|||
|
|
- `simulate_protanopia/deuteranopia/tritanopia()` - Color blindness
|
|||
|
|
- `distance_cie76()`, `distance_ciede2000()` - Perceptual distance
|
|||
|
|
|
|||
|
|
### Color Space Conversions
|
|||
|
|
|
|||
|
|
**Implemented color spaces:**
|
|||
|
|
- RGB ↔ HSL (Hue, Saturation, Lightness)
|
|||
|
|
- RGB ↔ HSV (Hue, Saturation, Value)
|
|||
|
|
- RGB → XYZ → Lab (CIELab, perceptually uniform)
|
|||
|
|
- Lab → LCH (Lightness, Chroma, Hue)
|
|||
|
|
|
|||
|
|
**Conversion accuracy:**
|
|||
|
|
- Uses D65 illuminant for XYZ conversions
|
|||
|
|
- Implements proper gamma correction for sRGB
|
|||
|
|
- Perceptually accurate Lab/LCH calculations
|
|||
|
|
|
|||
|
|
### Named Colors (`src/named.rs`)
|
|||
|
|
|
|||
|
|
Contains 148 CSS/X11 named colors as const data:
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
pub const NAMED_COLORS: &[NamedColor] = &[
|
|||
|
|
NamedColor { name: "red", hex: "#ff0000" },
|
|||
|
|
// ... 147 more
|
|||
|
|
];
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## WASM Bindings (`src/lib.rs`)
|
|||
|
|
|
|||
|
|
All exported functions are annotated with `#[wasm_bindgen]`:
|
|||
|
|
|
|||
|
|
**Categories:**
|
|||
|
|
1. **Color Information** - `parse_color()`
|
|||
|
|
2. **Color Manipulation** - `lighten_color()`, `darken_color()`, etc.
|
|||
|
|
3. **Color Generation** - `generate_random_colors()`, `generate_gradient()`, `generate_palette()`
|
|||
|
|
4. **Accessibility** - `get_text_color()`, `simulate_*()`, `calculate_contrast()`
|
|||
|
|
5. **Named Colors** - `get_all_named_colors()`, `search_named_colors()`
|
|||
|
|
6. **Utilities** - `color_distance()`, `version()`
|
|||
|
|
|
|||
|
|
**Return types:**
|
|||
|
|
- Simple functions return `Result<String, JsValue>` (hex colors)
|
|||
|
|
- Complex functions return `Result<JsValue, JsValue>` (serialized objects)
|
|||
|
|
- Uses `serde_wasm_bindgen` for JS ↔ Rust serialization
|
|||
|
|
|
|||
|
|
## Building
|
|||
|
|
|
|||
|
|
### Prerequisites
|
|||
|
|
```bash
|
|||
|
|
# Install Rust
|
|||
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
|||
|
|
|
|||
|
|
# Install wasm-pack
|
|||
|
|
cargo install wasm-pack
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Build Commands
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Build for bundler (Webpack, Rollup, Vite)
|
|||
|
|
wasm-pack build --target bundler --out-dir pkg
|
|||
|
|
|
|||
|
|
# Build for web (vanilla JS)
|
|||
|
|
wasm-pack build --target web --out-dir pkg-web
|
|||
|
|
|
|||
|
|
# Build for Node.js
|
|||
|
|
wasm-pack build --target nodejs --out-dir pkg-node
|
|||
|
|
|
|||
|
|
# Build all targets
|
|||
|
|
npm run build:all
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Build Configuration
|
|||
|
|
|
|||
|
|
**Cargo.toml optimizations:**
|
|||
|
|
- `opt-level = "s"` - Optimize for size
|
|||
|
|
- `lto = true` - Link-time optimization
|
|||
|
|
- `codegen-units = 1` - Better optimization
|
|||
|
|
- `strip = true` - Remove debug symbols
|
|||
|
|
|
|||
|
|
**wasm-opt flags:**
|
|||
|
|
- `--enable-bulk-memory` - Memory operations
|
|||
|
|
- `--enable-nontrapping-float-to-int` - Modern WASM features
|
|||
|
|
- `-Os` - Optimize for size
|
|||
|
|
|
|||
|
|
## Dependencies
|
|||
|
|
|
|||
|
|
**Core dependencies:**
|
|||
|
|
- `wasm-bindgen = "0.2"` - Rust ↔ JavaScript interop
|
|||
|
|
- `serde = "1.0"` - Serialization framework
|
|||
|
|
- `serde-wasm-bindgen = "0.6"` - JS object serialization
|
|||
|
|
- `rand = "0.8"` - Random number generation
|
|||
|
|
- `getrandom = { version = "0.2", features = ["js"] }` - WASM-compatible RNG
|
|||
|
|
- `js-sys = "0.3"` - JavaScript standard library bindings
|
|||
|
|
- `web-sys = "0.3"` - Web API bindings
|
|||
|
|
- `console_error_panic_hook = "0.1"` - Better panic messages in browser
|
|||
|
|
|
|||
|
|
## Testing
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Run tests in headless browsers
|
|||
|
|
wasm-pack test --headless --firefox --chrome
|
|||
|
|
|
|||
|
|
# Run tests in specific browser
|
|||
|
|
wasm-pack test --firefox
|
|||
|
|
wasm-pack test --chrome
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Publishing
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Build and test
|
|||
|
|
npm run build
|
|||
|
|
npm test
|
|||
|
|
|
|||
|
|
# Publish to npm
|
|||
|
|
wasm-pack pack
|
|||
|
|
wasm-pack publish
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Integration with pastel-ui
|
|||
|
|
|
|||
|
|
The `pastel-ui` Next.js application uses this WASM module instead of the REST API:
|
|||
|
|
|
|||
|
|
**Migration steps:**
|
|||
|
|
1. Install: `npm install pastel-wasm`
|
|||
|
|
2. Import: `import * as pastel from 'pastel-wasm'`
|
|||
|
|
3. Initialize: Call `await pastel.init()` on app load
|
|||
|
|
4. Replace API calls with direct WASM functions
|
|||
|
|
5. Update types (WASM returns simpler structures than API)
|
|||
|
|
|
|||
|
|
**Benefits for pastel-ui:**
|
|||
|
|
- **Performance**: 0ms latency vs 50-200ms API calls
|
|||
|
|
- **Reliability**: No network errors, works offline
|
|||
|
|
- **Cost**: Zero server costs, no rate limiting
|
|||
|
|
- **Privacy**: Color data never leaves the browser
|
|||
|
|
|
|||
|
|
## Development Workflow
|
|||
|
|
|
|||
|
|
### Adding a New Function
|
|||
|
|
|
|||
|
|
1. **Implement in color.rs:**
|
|||
|
|
```rust
|
|||
|
|
impl Color {
|
|||
|
|
pub fn my_new_operation(&self) -> Self {
|
|||
|
|
// implementation
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. **Add WASM binding in lib.rs:**
|
|||
|
|
```rust
|
|||
|
|
#[wasm_bindgen]
|
|||
|
|
pub fn my_new_operation(color: &str) -> Result<String, JsValue> {
|
|||
|
|
let c = Color::parse(color).map_err(|e| JsValue::from_str(&e))?;
|
|||
|
|
Ok(c.my_new_operation().to_hex())
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
3. **Rebuild:**
|
|||
|
|
```bash
|
|||
|
|
wasm-pack build --target bundler --out-dir pkg
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
4. **Test in example.html:**
|
|||
|
|
```javascript
|
|||
|
|
const result = pastel.my_new_operation('#ff0099');
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Debugging
|
|||
|
|
|
|||
|
|
**Rust errors:**
|
|||
|
|
```bash
|
|||
|
|
# Check for compile errors
|
|||
|
|
cargo check
|
|||
|
|
|
|||
|
|
# Run clippy for lints
|
|||
|
|
cargo clippy
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**WASM errors:**
|
|||
|
|
- Enable panic hook: `pastel.init()` calls `console_error_panic_hook::set_once()`
|
|||
|
|
- Check browser console for panics
|
|||
|
|
- Use `console.log()` via `web_sys::console::log_1()`
|
|||
|
|
|
|||
|
|
## Performance Considerations
|
|||
|
|
|
|||
|
|
**Fast operations** (< 0.1ms):
|
|||
|
|
- Color parsing
|
|||
|
|
- Simple manipulations (lighten, darken, saturate)
|
|||
|
|
- Color space conversions
|
|||
|
|
- Hex formatting
|
|||
|
|
|
|||
|
|
**Medium operations** (< 1ms):
|
|||
|
|
- Gradient generation (10 steps)
|
|||
|
|
- Palette generation
|
|||
|
|
- Color distance calculations
|
|||
|
|
|
|||
|
|
**Memory:**
|
|||
|
|
- Each Color instance: 32 bytes (4 × f64)
|
|||
|
|
- Named colors array: ~10KB (static data)
|
|||
|
|
- WASM memory grows dynamically as needed
|
|||
|
|
|
|||
|
|
## Common Issues
|
|||
|
|
|
|||
|
|
### Build Fails with "errno not supported"
|
|||
|
|
|
|||
|
|
**Cause**: Using pastel library directly (has CLI dependencies)
|
|||
|
|
**Solution**: Use custom color implementation (already done)
|
|||
|
|
|
|||
|
|
### wasm-opt validation errors
|
|||
|
|
|
|||
|
|
**Cause**: Missing WASM features
|
|||
|
|
**Solution**: Add flags in Cargo.toml:
|
|||
|
|
```toml
|
|||
|
|
[package.metadata.wasm-pack.profile.release]
|
|||
|
|
wasm-opt = ["-Os", "--enable-mutable-globals", "--enable-bulk-memory", "--enable-nontrapping-float-to-int"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Random number generation fails in browser
|
|||
|
|
|
|||
|
|
**Cause**: Missing JS feature flag for getrandom
|
|||
|
|
**Solution**: Add to Cargo.toml:
|
|||
|
|
```toml
|
|||
|
|
getrandom = { version = "0.2", features = ["js"] }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Future Enhancements
|
|||
|
|
|
|||
|
|
### Planned Features
|
|||
|
|
- [ ] More color harmony schemes (square, split, analogous)
|
|||
|
|
- [ ] Color palettes from images (requires image parsing)
|
|||
|
|
- [ ] CMYK color space support
|
|||
|
|
- [ ] Color name lookup (closest named color)
|
|||
|
|
- [ ] Gradient interpolation in different color spaces (Lab, LCH)
|
|||
|
|
- [ ] Batch processing optimizations
|
|||
|
|
|
|||
|
|
### Optimization Opportunities
|
|||
|
|
- [ ] SIMD operations for batch processing
|
|||
|
|
- [ ] Lazy loading of named colors
|
|||
|
|
- [ ] Memoization of expensive calculations
|
|||
|
|
- [ ] WebWorker support for heavy operations
|
|||
|
|
|
|||
|
|
## Resources
|
|||
|
|
|
|||
|
|
- [wasm-bindgen Book](https://rustwasm.github.io/wasm-bindgen/)
|
|||
|
|
- [Color Science](https://en.wikipedia.org/wiki/CIE_1931_color_space)
|
|||
|
|
- [CIEDE2000 Algorithm](https://en.wikipedia.org/wiki/Color_difference#CIEDE2000)
|
|||
|
|
- [WCAG Contrast](https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**Project Status**: Production-ready
|
|||
|
|
**Last Updated**: 2025-01-17
|