README.md

# Isotope

![CI Status](https://github.com/viniciusmuller/isotope/actions/workflows/ci.yml/badge.svg)

Isotope is a library that provides Elixir bindings to the [bracket-noise](https://crates.io/crates/bracket-noise) crate, which is a Rust port of [FastNoise Lite](https://github.com/Auburn/FastNoiseLite).

Noise maps are returned as compact binaries of packed `f32` values (~4 bytes per value), making them suitable for generating large maps without excessive memory usage.

## Installation

The package can be installed by adding `isotope` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:isotope, "~> 0.3.0"}
  ]
end
```
And running `mix deps.get && mix deps.compile`.

## Usage

### Generating a Noise Map

```elixir
opts = %Isotope.Options{
  seed: 42,
  noise_type: :simplex_fractal,
  frequency: 0.01,
  fractal_options: %Isotope.Options.Fractal{octaves: 4}
}

{:ok, noise} = Isotope.Noise.new(opts)

# Returns an %Isotope.NoiseMap{} struct
nm = Isotope.Noise.noise_map(noise, {1000, 1000})
```

### Accessing Values

```elixir
# Single value at column x, row y
Isotope.NoiseMap.get(nm, 50, 50)

# Entire row as a list of floats
Isotope.NoiseMap.row(nm, 0)

# Dimensions
{width, height} = Isotope.NoiseMap.size(nm)

# Convert to nested list [[float()]]
Isotope.NoiseMap.to_list(nm)
```

### Using with Enum

`Isotope.NoiseMap` implements `Enumerable`, iterating over rows:

```elixir
# Average value per row
Enum.map(nm, fn row -> Enum.sum(row) / length(row) end)

# Visualize in the terminal
Isotope.Utils.show_noisemap(nm)
```

### Chunks (Infinite Worlds / Tiling)

Generate a noise map starting at an arbitrary coordinate:

```elixir
chunk = Isotope.Noise.chunk(noise, {512, 512}, 256, 256)
```

### Sampling Individual Points

```elixir
# 2D
value = Isotope.Noise.get_noise(noise, {1.5, 2.5})

# 3D
value = Isotope.Noise.get_noise(noise, {1.5, 2.5, 3.5})
```

### Noise Types

Isotope supports the following noise types via the `:noise_type` option:

| Type | Atom |
|------|------|
| Simplex (OpenSimplex2) | `:simplex` |
| Simplex Fractal | `:simplex_fractal` |
| Perlin | `:perlin` |
| Perlin Fractal | `:perlin_fractal` |
| Value | `:value` |
| Value Fractal | `:value_fractal` |
| Cubic | `:cubic` |
| Cubic Fractal | `:cubic_fractal` |
| Cellular (Voronoi) | `:cellular` |
| White Noise | `:white` |

### Options

See `Isotope.Options`, `Isotope.Options.Fractal`, and `Isotope.Options.Cellular` for all available configuration.

```elixir
%Isotope.Options{
  seed: 1337,               # Random seed
  noise_type: :simplex,     # Noise algorithm
  frequency: 0.01,          # Controls noise scale
  interpolation: :quintic,  # :linear | :hermite | :quintic
  fractal_options: %Isotope.Options.Fractal{
    fractal_type: :fbm,     # :fbm | :billow | :rigid_multi
    octaves: 3,             # Number of fractal layers
    lacunarity: 2.0,        # Frequency multiplier per octave
    gain: 0.5               # Amplitude multiplier per octave
  },
  cellular_options: %Isotope.Options.Cellular{
    distance_function: :euclidean,  # :euclidean | :manhattan | :natural
    return_type: :cell_value,       # :cell_value | :distance | :distance2 | ...
    distance_indices: {0, 1},
    jitter: 0.45
  }
}
```

For more information, check the documentation
[here](https://hexdocs.pm/isotope).

## Examples
You can check and run the examples in the `examples` folder.
```bash
mix run examples/<example>.exs
```

## Images
![Output of the terrain.exs example script](images/terrain.png)
![Output of the visualization.exs example script](images/visualization.png)