# Scribe Shaders

A collection of interactive WebGL shaders used at [Scribe](https://scribehow.com/).

Shaders are built with [OGL](https://github.com/oframe/ogl)—a lightweight WebGL Library—and [Tweakpane](https://tweakpane.github.io/docs/), dev tool for fine-tuning parameters.

## Installation

```bash
npm install @scribehow/shaders
# or
yarn add @scribehow/shaders
```

## Usage

### Basic Usage

```javascript
import { FluidLight } from '@scribehow/shaders';

const canvas = document.getElementById('canvas');

if (canvas) {
  const shader = await FluidLight.create(canvas, {
    // Config options
  });
}
```

### React Usage

```typescript
import { useRef, useEffect, useState } from 'react';
import { FluidLight, type FluidLightShader } from '@scribehow/shaders';

export const FluidLightBackground = () => {
  const canvasRef = useRef<HTMLCanvasElement>(null);

  useEffect(() => {
    if (!canvasRef.current) return;

    await FluidLight.create(canvasRef.current, {
      // Config options
    });
  }, [canvasRef]);

  return <canvas ref={canvasRef} className='size-full'></canvas>
}
```

### Script Tag

For usage without a bundler, the package provides a global build, with methods accessed through the global `ScribeShaders` namespace:

```html
<script src="https://cdn.jsdelivr.net/npm/@scribehow/shaders@latest/dist/browser/index.global.js"></script>
<script>
  const canvas = document.getElementById('canvas');

  if (canvas && typeof ScribeShaders !== 'undefined') {
    // Create shader using the `ScribeShaders` global namespace
    ScribeShaders.FluidLight.create(canvas, {
      // Config options
    }).then(shader => {
      console.log('Shader created!');
    });
  }
</script>
```

### Development Tools (Optional)

The package includes optional development tools powered by Tweakpane for real-time parameter adjustment. These tools are **not bundled** unless you explicitly enable them and install the required dependencies.

#### Installing Development Dependencies

If you want to use the development tools, install the optional peer dependencies:

```bash
npm install tweakpane @tweakpane/plugin-essentials
# or
yarn add tweakpane @tweakpane/plugin-essentials
```

#### Enabling Development Tools

```javascript
import { FluidLight } from '@scribehow/shaders';

const canvas = document.getElementById('canvas');

if (canvas) {
  const shader = await FluidLight.create(canvas, {
    // Config options
  });

  await FluidLight.attachDevtools(shader);
}
```

**Note:** If you haven't installed the Tweakpane dependencies, the `attachDevtools` call will fail gracefully.

# API Reference

## `FluidLight`

[View Preview](https://stylus.design/fluid-light)

### `FluidLight.create(canvas, config?)`

Creates a new FluidLight shader instance.

**Parameters:**
- `canvas` (`HTMLCanvasElement`): The canvas element to render to
- `config` (`Partial<FluidLightConfig>`, optional): Configuration 
options

**Returns:** `Promise<FluidLightShader>`

### `FluidLight.attachDevtools(shader)`

**Parameters:**
- `shader` (`FluidLightShader`): The shader instance to attach 
devtools to

**Returns:** `Promise<DevtoolsInstance>`

### `FluidLightConfig`

The second argument passed into `FluidLight.create()` is `FluidLightConfig` — an object which allows adjusting the colors, movement, distortion, and other effects of the shader. The default settings are below.

```javascript
await FluidLight.create(canvas, {
  // Side to orient effects around
  // 0 = bottom, 1 = top, 2 = right, 3 = left
  side: 0,                 

  // Background color
  background: "#020617",

  // Light wave configuration
  lightWave: {
    amplitude: 0.04,      // Wave height/intensity
    speed: 0.4,           // Animation speed
    frequency: 1.2,       // Wave frequency/density
    color1: "#5648FB",    // Outermost color
    color2: "#3AC3FF",    // Second color
    color3: "#CE7FFF",    // Third color
    color4: "#F45397",    // Fourth color
    color5: "#FFB525",    // Center color
    minFalloff: 6.0,      // Minimum falloff intensity
    maxFalloff: 8.0,      // Maximum falloff intensity
  },

  // Echo / ripple effect configuration
  echo: {                  
    enabled: true,
    offset: 0.1,          // Distance from edge
    radius: 0.9,          // Initial radius
    frequency: 20.0,      // Ripple frequency
    ringSize: 2.0,        // Ring thickness
    strokeOpacity: 0.2,   // Ring stroke opacity
    fillOpacity: 0.01,    // Ring fill opacity
    animateIn: true,      // Animate entrance
    animationDuration: 3000,  // Animation duration (ms)
    animationDelay: 200,  // Animation delay (ms)
  },
});
```
