# Algorithmic Filters

This directory contains JavaScript-based filters that can be applied to the canvas or selection.

## Filter Structure

All filters must follow this structure:

```javascript
const filter = {
    // Required fields
    name: "Filter Name",           // Display name (string)
    apply: function(selectionInfo) { /* ... */ },  // Main processing function

    // Optional fields
    description: "Detailed description...",  // Multi-line description
    category: "category",          // "warp", "color", "stylize", "adjust", etc.
    version: "1.0.0",             // Semantic version
    author: "Your Name",          // Author name

    // Parameters (optional)
    params: {
        paramName: {
            type: "number",        // "number", "color", "colorRange", "boolean", "string", "selection"
            default: 10,           // Default value
            label: "Label",        // Display label
            min: 0,               // Min value (for number)
            max: 100              // Max value (for number)
        }
        // ... more parameters
    }
};

// Register filter
pixcen.registerFilter(filter);
```

## Selection Info

The `apply()` function receives a `selectionInfo` object:

```javascript
{
    x: 0,              // Selection top-left X
    y: 0,              // Selection top-left Y
    width: 320,        // Selection width
    height: 200,       // Selection height
    hasLasso: false    // True if lasso selection active
}
```

## Canvas Access API

Filters use the existing pixcen.canvas API for pixel manipulation:

```javascript
apply: function(selectionInfo) {
    // Iterate over selection
    for (let y = 0; y < selectionInfo.height; y++) {
        for (let x = 0; x < selectionInfo.width; x++) {
            // Read pixel
            const color = pixcen.canvas.getPixel(
                selectionInfo.x + x,
                selectionInfo.y + y
            );

            // Transform color
            const newColor = transformColor(color);

            // Write pixel
            pixcen.canvas.setPixel(
                selectionInfo.x + x,
                selectionInfo.y + y,
                newColor
            );
        }
    }
}
```

## Parameter Types

- **number**: Numeric value with min/max range
- **color**: C64 color palette index (0-15)
- **colorRange**: Color range index (0-31)
- **boolean**: True/false checkbox
- **string**: Text input
- **selection**: Dropdown with predefined options

### Example Parameters

```javascript
params: {
    intensity: {
        type: "number",
        default: 50,
        label: "Intensity %",
        min: 0,
        max: 100
    },
    foregroundColor: {
        type: "color",
        default: 1,
        label: "Foreground Color"
    },
    invertColors: {
        type: "boolean",
        default: false,
        label: "Invert Colors"
    },
    direction: {
        type: "selection",
        default: "horizontal",
        label: "Direction",
        options: [
            { value: "horizontal", label: "Horizontal" },
            { value: "vertical", label: "Vertical" }
        ]
    }
}
```

## Available APIs

See `scripts/README.md` for full API documentation. Common functions:

- `pixcen.canvas.getPixel(x, y)` - Get pixel color (0-15)
- `pixcen.canvas.setPixel(x, y, color)` - Set pixel color
- `pixcen.canvas.getWidth()` / `getHeight()` - Canvas dimensions
- `pixcen.colors.getPalette()` - Get color palette
- `pixcen.ui.log(message)` - Log to output window

## Best Practices

1. **Always validate coordinates** - Check bounds before getPixel/setPixel
2. **Use buffers for complex transforms** - Store original pixels if you need to read neighbors
3. **Access parameters via this.params** - Example: `this.params.intensity`
4. **Handle edge cases** - Consider empty selections, single pixels, etc.
5. **Optimize loops** - C64 canvases are small (320x200 max) but still optimize where possible
6. **Add progress logging** - Use `pixcen.ui.log()` for debugging

## Example: Simple Invert Filter

```javascript
const filter = {
    name: "Invert Colors",
    description: "Inverts all colors in the selection",
    category: "color",
    version: "1.0.0",
    author: "Example",

    apply: function(selectionInfo) {
        for (let y = 0; y < selectionInfo.height; y++) {
            for (let x = 0; x < selectionInfo.width; x++) {
                const color = pixcen.canvas.getPixel(
                    selectionInfo.x + x,
                    selectionInfo.y + y
                );
                pixcen.canvas.setPixel(
                    selectionInfo.x + x,
                    selectionInfo.y + y,
                    15 - color  // Invert (0→15, 1→14, ..., 15→0)
                );
            }
        }
    }
};

pixcen.registerFilter(filter);
```

## Example: Pixelate Filter with Parameters

```javascript
const filter = {
    name: "Pixelate",
    description: "Creates a pixelated/mosaic effect",
    category: "stylize",
    version: "1.0.0",
    author: "Example",

    params: {
        blockSize: {
            type: "number",
            default: 4,
            label: "Block Size",
            min: 2,
            max: 16
        }
    },

    apply: function(selectionInfo) {
        const blockSize = this.params.blockSize;

        // Process in blocks
        for (let by = 0; by < selectionInfo.height; by += blockSize) {
            for (let bx = 0; bx < selectionInfo.width; bx += blockSize) {
                // Count color frequencies in block
                const colorCounts = new Array(16).fill(0);

                for (let dy = 0; dy < blockSize; dy++) {
                    for (let dx = 0; dx < blockSize; dx++) {
                        const x = selectionInfo.x + bx + dx;
                        const y = selectionInfo.y + by + dy;

                        if (bx + dx < selectionInfo.width && by + dy < selectionInfo.height) {
                            const color = pixcen.canvas.getPixel(x, y);
                            colorCounts[color]++;
                        }
                    }
                }

                // Find most common color
                let maxCount = 0;
                let mostCommonColor = 0;
                for (let c = 0; c < 16; c++) {
                    if (colorCounts[c] > maxCount) {
                        maxCount = colorCounts[c];
                        mostCommonColor = c;
                    }
                }

                // Fill block with most common color
                for (let dy = 0; dy < blockSize; dy++) {
                    for (let dx = 0; dx < blockSize; dx++) {
                        const x = selectionInfo.x + bx + dx;
                        const y = selectionInfo.y + by + dy;

                        if (bx + dx < selectionInfo.width && by + dy < selectionInfo.height) {
                            pixcen.canvas.setPixel(x, y, mostCommonColor);
                        }
                    }
                }
            }
        }
    }
};

pixcen.registerFilter(filter);
```

## Testing Your Filter

1. Save your filter as `my_filter.js` in this directory
2. Restart Pixcen (filters are scanned on startup)
3. Go to **Filters → Algorithmic...**
4. Select your filter from the list
5. Adjust parameters (if any)
6. Click OK to apply

## Debugging

- Use `pixcen.ui.log(message)` to log debug information
- Check the Output window (View → Output) for logs and errors
- Test with different selection types (full canvas, rectangular, lasso)
- Test edge cases (empty selections, single pixels, large selections)

## Categories

Suggested categories for organizing filters:

- **color** - Color manipulation (invert, hue shift, etc.)
- **adjust** - Brightness, contrast, levels, etc.
- **stylize** - Artistic effects (pixelate, posterize, etc.)
- **warp** - Coordinate transformations (wave, twist, etc.)
- **noise** - Noise addition/removal
- **blur** - Blur and sharpen effects
- **edge** - Edge detection and enhancement

## See Also

- `scripts/README.md` - Complete Pixcen scripting API documentation
- `scripts/shaders/` - Shader examples (per-pixel processing)
- `scripts/brushes/` - Brush examples (generative patterns)
