main 91a8269706f3 cached
3 files
12.7 KB
3.6k tokens
7 symbols
1 requests
Download .txt
Repository: lorenSchmidt/fractal_cell_noise
Branch: main
Commit: 91a8269706f3
Files: 3
Total size: 12.7 KB

Directory structure:
gitextract_567aoidz/

├── LICENSE
├── README.md
└── fractal_cell_noise.js

================================================
FILE CONTENTS
================================================

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2022 lorenSchmidt

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# octavia noise
a fractal noise algorithm named after a very nice cat

![Screenshot](twelve_octaves_thumb.png)

this is functionally similar to well known fractal noise algorithms such as value noise, perlin noise, or simplex noise, but does not exhibit the same grid artifacts. it's useful for situations which benefit from organic feature placement or very natural slope distribution (when using perlin or value noise in slope-intensive applications, grid artifacts can be a problem). 

this is most closely related to cellular noise algorithms such as worley noise.

## parameters
this has the parameters you'd expect from perlin or value noise: octaves and amplitude ratio (aka roughness or persistence). because the structure of it is so different, it also has several other tuning parameters which can yield interesting textural effects.

### octaves
![Screenshot](octaves.png)
like perlin or value noise, this adds successively finer features via additional layers of noise. this affects speed- it's linearly slower the more octaves are combined. right to left: one octave, six, twelve.

### amplitude ratio
![Screenshot](amplitude_ratio.png)
this is also known as roughness or persistence. this governs how the octaves are combined. finer octaves have this height relative to the next size up. left to right: 3/8, 1/2, 5/8. lower values will allow the lower frequencies to define the texture, while higher favor the finer details. 1/2 is default, which will yield an amplitude series of 1, 1/2, 1/4, 1/8, 1/16...

### softness
![Screenshot](softness.png)
0-1. this governs the falloff used for each sample point. the default is 1, which is as continuous as possible. lower softness values can result in steeper, more defined grains, pits, or spires. 

### samples
space is partitioned into squares. this controls how many samples are placed within each. the radius of each sample is 1, relative to square edge length, so coverage is high, and they overlap significantly with neighboring squares. 2-4 samples will give you decent coverage unless the softness is very low. the algorithm is linearly slower the more samples are placed.

### bias, range
![Screenshot](bias_range.png)
these parameters set the height of each sample. bias is the base value, and range is a random spread above and below it. 0 range will make every sample be exactly the same height. left to right: -1 bias, range 0, 1 bias, range 0, 0 bias, range 1


================================================
FILE: fractal_cell_noise.js
================================================
/* 
--------------------------------------------------------------------------------

octavia noise

--------------------------------------------------------------------------------

this is the heart of the cellular noise algorithm. it's a single x, y lookup. the noise loops on itself, and is a rectangle xsize by ysize. x and y are the current point in space we are calculating for (floating point is fine). the space is divided into squares. n points are deterministically placed             
+---------+ in the square ("samples" controls this). each is given a random 
|   x     | height, by default -1 to 1. a soft 0-1 kernel is centered on each. 
|         | it has a diameter equal to the square size, outside of which it 
|x     x  | falls off cleanly to 0. 
|  x      | 
+---------+ d is density- at density 1 you have 1 square for the entire texture space. at density 2 it's 2 squares by 2, etc.. seed is the seed for this octave. softness alters the shape of the falloff (but it always has the same diameter). the heights can be customized customized by setting the bias value (center) and range (it goes from bias - range to bias + range)   */

// this variant uses a trick to reduce samples
// sample radius is 1/2 square edge instead of 1, which makes overlap from neighboring cells never more than 1/2 square length. this means we can check which quadrant we're in and only check the three nearest neighbors, instead of all 8 neighbors.
function curve_stack_2x2_xy(x, y, xsize = 256, ysize = 256, d = 1, seed = 0, softness = 1, samples = 4, bias = 0, range = 1 ) {

    x /= xsize; y /= xsize 
    let ix = Math.floor(x * d); let iy = Math.floor(y * d)
    let ti = 0 // random number table index
    let dm1 = d - 1 // for the bitwise & instead of % range trick

    c_height = 0

    // this variant uses a trick to reduce samples
    // sample radius is 1/2 square edge instead of 1, which makes overlap from neighboring cells never more than 1/2 square length. this means we can check which quadrant we're in and only check the three nearest neighbors, instead of all 8 neighbors.
    let left = ix - 1 + (Math.floor(x * 2 * d) & 1)
    let top = iy - 1 + (Math.floor(y * 2 * d) & 1)
    let right = left + 1; let bottom = top + 1

    // this uses every point within the radius. when doing worley noise, we calculate distances for each point, and compare, getting various other parameters per point. instead, we can drop the distance comparisons, and instead get a height per point and run it through a lightweight kernel, and accumulate
    let px, py, distance_squared, amp
    let cx = left, cy = top
    let sum = 0
    while (cy <= bottom) {
        cx = left
        while (cx <= right) {
            // this is a deterministic noise function with two integer inputs
            ti = pos3int((cx + d) & dm1, (cy + d) & dm1, noise_seed)
            // seed our rng with that value
        
            // this bounded curve runs from -1 to 1. i believe this means that we want to multiply the distance by d. however, this seems to leave seams? maybe i am wrong about the numbers.
            for (let a = 0; a < samples; a ++) {
                px = cx / d + noise_table[(ti ++) & nt_sizem1] / nt_size / d
                py = cy / d + noise_table[(ti ++) & nt_sizem1] / nt_size / d
                distance_squared = d * d * ((x - px) ** 2 + (y - py) ** 2) * 4
                
                let h = bias + -range + 2 * range * noise_table[(ti ++) % nt_size] / nt_size
                // this is a bounded -1 to 1 variant of the witch of agnesi. this will prevent seams when points drop out of the set.
                if (distance_squared < 1.0) {
                    amp = (softness * (1 - distance_squared) / (softness + distance_squared))
                    amp = amp * amp
                    // note that this worked ^ 2, but the derivative was not 0 at -1 and 1
                    sum += h * amp
                }
            }
            cx ++
        }
        cy ++
    }

    return sum
}


function curve_stack_3x3_xy(x, y, xsize = 256, ysize = 256, d = 1, seed = 0, softness = 1, samples = 4, bias = 0, range = 1 ) {

    x /= xsize; y /= xsize 
    let ix = Math.floor(x * d); let iy = Math.floor(y * d)
    let ti = 0 // random number table index

    c_height = 0

    // this uses every point within the radius. when doing worley noise, we calculate distances for each point, and compare, getting various other parameters per point. instead, we can drop the distance comparisons, and instead get a height per point and run it through a lightweight kernel, and accumulate
    for (let oy = -1; oy <= 1; oy ++) {
        for (let ox = -1; ox <= 1; ox ++) {
            let cx = ix + ox; let cy = iy + oy
            // this is a deterministic noise function with two integer inputs
            ti = pos3int((cx + d) % d, (cy + d) % d, noise_seed)
            // seed our rng with that value
        
            // let count = 1 + prime_cycle() % (samples - 1)
            let count = samples
            // this bounded curve runs from -1 to 1. i believe this means that we want to multiply the distance by d. however, this seems to leave seams? maybe i am wrong about the numbers.
            for (let a = 0; a < count; a ++) {
                let px = cx / d + (noise_table[(ti ++) % nt_size] / nt_size) / d 
                let py = cy / d + (noise_table[(ti ++) % nt_size] / nt_size) / d
                let distance = d * Math.sqrt((x - px) ** 2 + (y - py) ** 2) 
                let height = bias + -range + 2 * range * noise_table[(ti ++) % nt_size] / nt_size
                // this is a bounded -1 to 1 variant of the witch of agnesi. this will prevent seams when points drop out of the set.
                if (distance < 1.0) {
                    let a = (softness * (1 - distance * distance) 
                            / (softness + distance * distance))
                    a = a * a
                    // note that this worked ^ 2, but the derivative was not 0 at -1 and 1
                    c_height += height * a
                }
            }
        }
    }

    return c_height
}


var stack_octaves = 1
function cell_noise_xy(x, y, xsize = 256, ysize = 256, density = 4, seed = 0,octaves = 2, amplitude_ratio = 1/2, softness = 1, samples = 4, bias = 0, range = 1 ) {
    let surface = 0
    for (let a = 0; a < octaves; a ++) {
        let octave_seed = noise_table[seed % nt_size] // inline prime cycle
        seed += pc_increment
        let layer = curve_stack_2x2_xy(x, y, xsize, ysize, density * 2 ** a, octave_seed, softness, samples, bias, range)

        surface += (amplitude_ratio ** a) * layer
    }

    c_height = 0.5 * surface
    return c_height
}
/* this evaluates as -1 to 1, very center-weighted
(seed 29477)
-1.0 - -0.9  ▓▓
-0.9 - -0.8  ▓▓
-0.8 - -0.7  ▓▓▓
-0.7 - -0.6  ▓▓▓▓▓
-0.6 - -0.5  ▓▓▓▓▓▓▓
-0.5 - -0.4  ▓▓▓▓▓▓▓▓
-0.4 - -0.3  ▓▓▓▓▓▓▓▓▓▓
-0.3 - -0.2  ▓▓▓▓▓▓▓▓▓▓▓▓▓
-0.2 - -0.1  ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
-0.1 -  0.0  ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
 0.0 -  0.1  ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
 0.1 -  0.2  ▓▓▓▓▓▓▓▓▓▓▓▓▓▓
 0.2 -  0.3  ▓▓▓▓▓▓▓▓▓▓▓▓
 0.3 -  0.4  ▓▓▓▓▓▓▓▓▓▓
 0.4 -  0.5  ▓▓▓▓▓▓▓▓▓
 0.5 -  0.6  ▓▓▓▓▓▓▓
 0.6 -  0.7  ▓▓▓▓▓
 0.7 -  0.8  ▓▓▓▓
 0.8 -  0.9  ▓▓▓
 0.9 -  1.0  ▓▓▓
*/


/* 
--------------------------------------------------------------------------------

positional random number generation

--------------------------------------------------------------------------------
for 2d value noise, we need to be able to input two coordinates and a seed, and
get a deterministic value for that point in space. you can substitute other
approaches for this one- this is a relatively simple, readable approach i came
up with but there are more cryptographically sound 3 input hashes out there.

note that if generalizing this for n dimensions, you'd want your number of dimensions plus one for the seed
*/

// three input positional rng. the output is an integer in the range 0-nt_size
function pos3int(x, y, seed) {
    let linear = (x % ns) + (y % ns) * ns + seed
    linear %= noise_table.length
    return noise_table[linear]
}


// used for table setup only
var seed = 88883
var noise_table = []
var ns = 256
var nt_size = ns * ns
var nt_sizem1 = nt_size - 1
function init_random_table() {
    let list = []
    for (let a = 0; a < nt_size; a ++) {
        list.push(a)
    }
    for (let a = 0; a < nt_size; a ++) {
        noise_table[a] = draw_card(list)
    }
}


// if you walk through a table, offsetting your index by a prime number which doesn't divide evenly into your table size, you will cycle through all the entries in the array exactly once, in a nonrepeating order. 
// there are three instances of this in the algorithm, all inline, but this self-contained function is here for clarity
var pc_increment = 101159
var pc_seed = 0
function prime_cycle() {
    let result = noise_table[pc_seed % nt_size]
    pc_seed += pc_increment
    return result
}


// used for table setup only
// picks a random element and returns it, removing it from the array
function draw_card(array) {
    var index = Math.floor(Math.random() * array.length);
    //console.log("index = " + index);
    var result = array[index];
    if (array.length > 0) {
        return (array.splice(index, 1))[0];
    }
    else
        return "ERROR: pick running on array of size 0";
}
Download .txt
gitextract_567aoidz/

├── LICENSE
├── README.md
└── fractal_cell_noise.js
Download .txt
SYMBOL INDEX (7 symbols across 1 files)

FILE: fractal_cell_noise.js
  function curve_stack_2x2_xy (line 18) | function curve_stack_2x2_xy(x, y, xsize = 256, ysize = 256, d = 1, seed ...
  function curve_stack_3x3_xy (line 68) | function curve_stack_3x3_xy(x, y, xsize = 256, ysize = 256, d = 1, seed ...
  function cell_noise_xy (line 109) | function cell_noise_xy(x, y, xsize = 256, ysize = 256, density = 4, seed...
  function pos3int (line 162) | function pos3int(x, y, seed) {
  function init_random_table (line 175) | function init_random_table() {
  function prime_cycle (line 190) | function prime_cycle() {
  function draw_card (line 199) | function draw_card(array) {
Condensed preview — 3 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (14K chars).
[
  {
    "path": "LICENSE",
    "chars": 1069,
    "preview": "MIT License\n\nCopyright (c) 2022 lorenSchmidt\n\nPermission is hereby granted, free of charge, to any person obtaining a co"
  },
  {
    "path": "README.md",
    "chars": 2434,
    "preview": "# octavia noise\na fractal noise algorithm named after a very nice cat\n\n![Screenshot](twelve_octaves_thumb.png)\n\nthis is "
  },
  {
    "path": "fractal_cell_noise.js",
    "chars": 9551,
    "preview": "/* \r\n--------------------------------------------------------------------------------\r\n\r\noctavia noise\r\n\r\n--------------"
  }
]

About this extraction

This page contains the full source code of the lorenSchmidt/fractal_cell_noise GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 3 files (12.7 KB), approximately 3.6k tokens, and a symbol index with 7 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!