Skip to content

Commit

Permalink
add hStartCenter feautre
Browse files Browse the repository at this point in the history
  • Loading branch information
meodai committed Dec 7, 2023
1 parent 0d0f1f2 commit 8c34d90
Show file tree
Hide file tree
Showing 10 changed files with 73 additions and 35 deletions.
80 changes: 54 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
# Rampensau 🐷

Color palette generation function using hue cycling and easing functions.
Rampensau is a color palette generation function that utilizes hue cycling and
easing functions to generate color ramps.

The perfect tool for generating color palettes for data visualizations, visual design, generative art, or just for fun.

![generated Rampensau color palettes Animation](./rampensau.gif)

Check out a simple [demo](https://codepen.io/meodai/pen/yLvgxQK?editors=0010) or see it in action over on [farbvelo](https://farbvelo.elastiq.ch/)
![generated Rampensau color palettes Animation](./rampensau.gif)

- [1000 Ramps](https://codepen.io/meodai/pen/ExQWwar?editors=0110) generated with Rampensau
- [Colorful Dots](https://codepen.io/loficodes/full/GRQWOEG) demo using [p5](https://p5js.org/) by [@davidfitzgibbon](https://github.com/davidfitzgibbon)
Check out a simple [demo](https://codepen.io/meodai/pen/yLvgxQK?editors=0010) or see it in action over on [farbvelo](https://farbvelo.elastiq.ch/).

## Installation

Rampensau is bundled as both UMD and ES on npm. Install it using npm:
Rampensau is bundled as both UMD and ES on npm. Install it using your package manager of choice:

```js
npm install rampensau
Expand All @@ -27,37 +28,64 @@ let generateRandomColorRamp = require("rampensau");
import { generateRandomColorRamp } from "rampensau";
```

Or include it directly in your HTML:

```html
<script src="https://cdn.jsdelivr.net/npm/rampensau/dist/index.js"></script>
<!-- or -->
<script type="module">
import { generateHSLRamp } from "https://cdn.jsdelivr.net/npm/rampensau/dist/index.mjs";
</script>
```

## Usage

```js
import { generateHSLRamp } from 'rampensau';

function generateHSLRamp ({
total : 9, // number of colors in the ramp
hStart : Math.random() * 360, // hue at the start of the ramp
hCycles : 1, // number of full hue cycles
// (.5 = 180°, 1 = 360°, 2 = 720°, etc.)
hEasing : (x, fr) => x, // hue easing function

sRange : [0.4, 0.35], // saturation range
sEasing : (x, fr) => Math.pow(x, 2), // saturation easing function

lRange : [Math.random() * 0.1, 0.9], // lightness range
lEasing : (x, fr) => Math.pow(x, 1.5), // lightness easing function
total : 9, // number of colors in the ramp
hStart : Math.random() * 360, // hue at the start of the ramp
hCycles : 1, // number of full hue cycles
// (.5 = 180°, 1 = 360°, 2 = 720°, etc.)
hCenter : 0.5, // where in the ramp the hue should be centered
hEasing : (x, fr) => x, // hue easing function

sRange : [0.4, 0.35], // saturation range
sEasing : (x, fr) => Math.pow(x, 2), // saturation easing function

lRange : [Math.random() * 0.1, 0.9], // lightness range
lEasing : (x, fr) => Math.pow(x, 1.5), // lightness easing function
});
```

### generateHSLRamp(Options{})

Function returns an array of colors in HSL format (`[0…360,0…1,0…1]`).
Function returns an array of colors in HSL format (`[0…360,0…1,0…1]`).
(But it can easily to any other cartesian color format)

#### Options

- `total` int 3…∞ → Amount of base colors.
- `hStart` float 03600 Red, 180 Teal etc..
- `hEasing` function(x) → Hue easing function
- `hCycles` float -∞…0…+∞ → Number of hue cycles. (.5 = 180°, 1 = 360°, 2 = 720°, etc.)
- `sRange` array [0…1,0…1] → Saturation Range
- `sEasing` function(x) → Saturation easing function
- `lRange` array [0…1,0…1] → Lightness Range
- `lEasing` function(x) → Saturation easing function
- `total` int 3…∞ → Amount of base colors.
- `hStart` float 0360 → Starting point of the hue ramp. 0 Red, 180 Teal etc..
- `hCenter`: float 01 → Center the hue in the color ramp.
- `hCycles` float -∞…0+∞ → Number of hue cycles. (.5 = 180°, 1 = 360°, 2 = 720°, etc.)
- `sRange` array [01,01] → Saturation Range
- `lRange` array [01,01] → Lightness Range

##### Hue Start & Center

The `hStart` sets the starting point of the hue ramp. The `hCenter` sets where in the hue in the ramp the should be centered. If your ramp starts with a high or low lightness, you might want to center the hue in the middle of the ramp. Thats is way the default value for `hCenter` is `0.5`. (In the center of a given ramp).

##### Easing Functions

Each of the color dimensions can be eased using a custom function.
The takes an input value `x` and returns a value between 0 and 1.:

- `hEasing` function(x) → Hue easing function
- `sEasing` function(x) → Saturation easing function
- `lEasing` function(x) → Saturation easing function

## License

Rampensau is distributed under the MIT License.
3 changes: 2 additions & 1 deletion dist/index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ __export(exports, {
function generateHSLRamp({
total = 9,
hStart = Math.random() * 360,
hStartCenter = 0.5,
hEasing = (x) => Math.pow(x, 2),
hCycles = 1,
sRange = [0.4, 0.35],
Expand All @@ -29,7 +30,7 @@ function generateHSLRamp({
return new Array(total).fill(0).map((_, i) => {
const relI = i / (total - 1);
return [
(360 + hStart + (1 - hEasing(relI, 1 / total)) * (360 * hCycles)) % 360,
(360 + hStart + (1 - hEasing(relI, 1 / total) - hStartCenter) * (360 * hCycles)) % 360,
sRange[0] + sDiff * sEasing(relI, 1 / total),
lRange[0] + lDiff * lEasing(relI, 1 / total)
];
Expand Down
3 changes: 2 additions & 1 deletion dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export declare type Vector3 = [number, number, number];
export declare type GenerateHSLRampArgument = {
total?: number;
hStart?: number;
hStartCenter?: number;
hCycles?: number;
hEasing?: ModifiedEasingFn;
sRange?: Vector2;
Expand All @@ -17,7 +18,7 @@ export declare type GenerateHSLRampArgument = {
* @param {GenerateHSLRampArgument} args - The arguments to generate the ramp.
* @returns {Array<number>} - The color ramp.
*/
export declare function generateHSLRamp({ total, hStart, hEasing, hCycles, sRange, sEasing, lRange, lEasing, }?: GenerateHSLRampArgument): Vector3[];
export declare function generateHSLRamp({ total, hStart, hStartCenter, hEasing, hCycles, sRange, sEasing, lRange, lEasing, }?: GenerateHSLRampArgument): Vector3[];
export declare function map(n: number, start1: number, stop1: number, start2: number, stop2: number): number;
export declare function scaleVector(vector: number[], originalScale?: [number, number][], targetScale?: [number, number][]): number[];
export declare function hslColorsToCSS(colors: Vector3[]): string[];
Expand Down
3 changes: 2 additions & 1 deletion dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var rampensau = (() => {
function generateHSLRamp({
total = 9,
hStart = Math.random() * 360,
hStartCenter = 0.5,
hEasing = (x) => Math.pow(x, 2),
hCycles = 1,
sRange = [0.4, 0.35],
Expand All @@ -31,7 +32,7 @@ var rampensau = (() => {
return new Array(total).fill(0).map((_, i) => {
const relI = i / (total - 1);
return [
(360 + hStart + (1 - hEasing(relI, 1 / total)) * (360 * hCycles)) % 360,
(360 + hStart + (1 - hEasing(relI, 1 / total) - hStartCenter) * (360 * hCycles)) % 360,
sRange[0] + sDiff * sEasing(relI, 1 / total),
lRange[0] + lDiff * lEasing(relI, 1 / total)
];
Expand Down
2 changes: 1 addition & 1 deletion dist/index.min.cjs
Original file line number Diff line number Diff line change
@@ -1 +1 @@
var f=Object.defineProperty;var a=n=>f(n,"__esModule",{value:!0});var M=(n,e)=>{a(n);for(var r in e)f(n,r,{get:e[r],enumerable:!0})};M(exports,{generateHSLRamp:()=>y,generateHSLRampParams:()=>V,hslColorsToCSS:()=>E,map:()=>x,scaleVector:()=>d});function y({total:n=9,hStart:e=Math.random()*360,hEasing:r=u=>Math.pow(u,2),hCycles:p=1,sRange:m=[.4,.35],sEasing:o=u=>Math.pow(u,2),lRange:t=[Math.random()*.1,.9],lEasing:s=u=>Math.pow(u,1.5)}={}){let u=t[1]-t[0],h=m[1]-m[0];return new Array(n).fill(0).map((L,i)=>{let b=i/(n-1);return[(360+e+(1-r(b,1/n))*(360*p))%360,m[0]+h*o(b,1/n),t[0]+u*s(b,1/n)]})}function x(n,e,r,p,m){return(n-e)/(r-e)*(m-p)+p}function d(n,e=[[0,360],[0,1],[0,1]],r=[[0,360],[0,100],[0,100]]){return n.map((p,m)=>{var o,t,s,u;return x(p,((o=e==null?void 0:e[m])==null?void 0:o[0])||0,((t=e==null?void 0:e[m])==null?void 0:t[1])||1,((s=r==null?void 0:r[m])==null?void 0:s[0])||0,((u=r==null?void 0:r[m])==null?void 0:u[1])||100)})}function E(n){return n.map(e=>{let[r,p,m]=d(e);return`hsl(${r}, ${p}%, ${m}%)`})}var V={hStart:{default:0,props:{min:0,max:360,step:.1}},hCycles:{default:1,props:{min:-1.25,max:1.5,step:.001}},minLight:{default:.1,props:{min:0,max:1,step:.001}},maxLight:{default:.9,props:{min:0,max:1,step:.001}},total:{default:5,props:{min:4,max:50,step:1}},minSaturation:{default:.4,props:{min:0,max:1,step:.001}},maxSaturation:{default:.35,props:{min:0,max:1,step:.001}}};
var x=Object.defineProperty;var M=n=>x(n,"__esModule",{value:!0});var y=(n,e)=>{M(n);for(var r in e)x(n,r,{get:e[r],enumerable:!0})};y(exports,{generateHSLRamp:()=>E,generateHSLRampParams:()=>L,hslColorsToCSS:()=>V,map:()=>d,scaleVector:()=>h});function E({total:n=9,hStart:e=Math.random()*360,hStartCenter:r=.5,hEasing:t=u=>Math.pow(u,2),hCycles:m=1,sRange:p=[.4,.35],sEasing:s=u=>Math.pow(u,2),lRange:o=[Math.random()*.1,.9],lEasing:b=u=>Math.pow(u,1.5)}={}){let u=o[1]-o[0],i=p[1]-p[0];return new Array(n).fill(0).map((C,a)=>{let f=a/(n-1);return[(360+e+(1-t(f,1/n)-r)*(360*m))%360,p[0]+i*s(f,1/n),o[0]+u*b(f,1/n)]})}function d(n,e,r,t,m){return(n-e)/(r-e)*(m-t)+t}function h(n,e=[[0,360],[0,1],[0,1]],r=[[0,360],[0,100],[0,100]]){return n.map((t,m)=>{var p,s,o,b;return d(t,((p=e==null?void 0:e[m])==null?void 0:p[0])||0,((s=e==null?void 0:e[m])==null?void 0:s[1])||1,((o=r==null?void 0:r[m])==null?void 0:o[0])||0,((b=r==null?void 0:r[m])==null?void 0:b[1])||100)})}function V(n){return n.map(e=>{let[r,t,m]=h(e);return`hsl(${r}, ${t}%, ${m}%)`})}var L={hStart:{default:0,props:{min:0,max:360,step:.1}},hCycles:{default:1,props:{min:-1.25,max:1.5,step:.001}},minLight:{default:.1,props:{min:0,max:1,step:.001}},maxLight:{default:.9,props:{min:0,max:1,step:.001}},total:{default:5,props:{min:4,max:50,step:1}},minSaturation:{default:.4,props:{min:0,max:1,step:.001}},maxSaturation:{default:.35,props:{min:0,max:1,step:.001}}};
2 changes: 1 addition & 1 deletion dist/index.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/index.min.mjs
Original file line number Diff line number Diff line change
@@ -1 +1 @@
function d({total:r=9,hStart:n=Math.random()*360,hEasing:t=u=>Math.pow(u,2),hCycles:m=1,sRange:e=[.4,.35],sEasing:o=u=>Math.pow(u,2),lRange:p=[Math.random()*.1,.9],lEasing:s=u=>Math.pow(u,1.5)}={}){let u=p[1]-p[0],i=e[1]-e[0];return new Array(r).fill(0).map((c,b)=>{let a=b/(r-1);return[(360+n+(1-t(a,1/r))*(360*m))%360,e[0]+i*o(a,1/r),p[0]+u*s(a,1/r)]})}function f(r,n,t,m,e){return(r-n)/(t-n)*(e-m)+m}function x(r,n=[[0,360],[0,1],[0,1]],t=[[0,360],[0,100],[0,100]]){return r.map((m,e)=>f(m,n?.[e]?.[0]||0,n?.[e]?.[1]||1,t?.[e]?.[0]||0,t?.[e]?.[1]||100))}function h(r){return r.map(n=>{let[t,m,e]=x(n);return`hsl(${t}, ${m}%, ${e}%)`})}var l={hStart:{default:0,props:{min:0,max:360,step:.1}},hCycles:{default:1,props:{min:-1.25,max:1.5,step:.001}},minLight:{default:.1,props:{min:0,max:1,step:.001}},maxLight:{default:.9,props:{min:0,max:1,step:.001}},total:{default:5,props:{min:4,max:50,step:1}},minSaturation:{default:.4,props:{min:0,max:1,step:.001}},maxSaturation:{default:.35,props:{min:0,max:1,step:.001}}};export{d as generateHSLRamp,l as generateHSLRampParams,h as hslColorsToCSS,f as map,x as scaleVector};
function h({total:e=9,hStart:n=Math.random()*360,hStartCenter:t=.5,hEasing:m=u=>Math.pow(u,2),hCycles:r=1,sRange:p=[.4,.35],sEasing:s=u=>Math.pow(u,2),lRange:a=[Math.random()*.1,.9],lEasing:i=u=>Math.pow(u,1.5)}={}){let u=a[1]-a[0],b=p[1]-p[0];return new Array(e).fill(0).map((d,f)=>{let o=f/(e-1);return[(360+n+(1-m(o,1/e)-t)*(360*r))%360,p[0]+b*s(o,1/e),a[0]+u*i(o,1/e)]})}function x(e,n,t,m,r){return(e-n)/(t-n)*(r-m)+m}function c(e,n=[[0,360],[0,1],[0,1]],t=[[0,360],[0,100],[0,100]]){return e.map((m,r)=>x(m,n?.[r]?.[0]||0,n?.[r]?.[1]||1,t?.[r]?.[0]||0,t?.[r]?.[1]||100))}function l(e){return e.map(n=>{let[t,m,r]=c(n);return`hsl(${t}, ${m}%, ${r}%)`})}var g={hStart:{default:0,props:{min:0,max:360,step:.1}},hCycles:{default:1,props:{min:-1.25,max:1.5,step:.001}},minLight:{default:.1,props:{min:0,max:1,step:.001}},maxLight:{default:.9,props:{min:0,max:1,step:.001}},total:{default:5,props:{min:4,max:50,step:1}},minSaturation:{default:.4,props:{min:0,max:1,step:.001}},maxSaturation:{default:.35,props:{min:0,max:1,step:.001}}};export{h as generateHSLRamp,g as generateHSLRampParams,l as hslColorsToCSS,x as map,c as scaleVector};
3 changes: 2 additions & 1 deletion dist/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
function generateHSLRamp({
total = 9,
hStart = Math.random() * 360,
hStartCenter = 0.5,
hEasing = (x) => Math.pow(x, 2),
hCycles = 1,
sRange = [0.4, 0.35],
Expand All @@ -14,7 +15,7 @@ function generateHSLRamp({
return new Array(total).fill(0).map((_, i) => {
const relI = i / (total - 1);
return [
(360 + hStart + (1 - hEasing(relI, 1 / total)) * (360 * hCycles)) % 360,
(360 + hStart + (1 - hEasing(relI, 1 / total) - hStartCenter) * (360 * hCycles)) % 360,
sRange[0] + sDiff * sEasing(relI, 1 / total),
lRange[0] + lDiff * lEasing(relI, 1 / total)
];
Expand Down
3 changes: 2 additions & 1 deletion dist/index.umd.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var rampensau = (() => {
function generateHSLRamp({
total = 9,
hStart = Math.random() * 360,
hStartCenter = 0.5,
hEasing = (x) => Math.pow(x, 2),
hCycles = 1,
sRange = [0.4, 0.35],
Expand All @@ -41,7 +42,7 @@ var rampensau = (() => {
return new Array(total).fill(0).map((_, i) => {
const relI = i / (total - 1);
return [
(360 + hStart + (1 - hEasing(relI, 1 / total)) * (360 * hCycles)) % 360,
(360 + hStart + (1 - hEasing(relI, 1 / total) - hStartCenter) * (360 * hCycles)) % 360,
sRange[0] + sDiff * sEasing(relI, 1 / total),
lRange[0] + lDiff * lEasing(relI, 1 / total)
];
Expand Down
7 changes: 6 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export type Vector3 = [number, number, number];
export type GenerateHSLRampArgument = {
total?: number;
hStart?: number;
hStartCenter?: number;
hCycles?: number;
hEasing?: ModifiedEasingFn;
sRange?: Vector2;
Expand All @@ -20,6 +21,7 @@ export type GenerateHSLRampArgument = {
export function generateHSLRamp({
total = 9,
hStart = Math.random() * 360,
hStartCenter = 0.5,
hEasing = (x) => Math.pow(x, 2),
hCycles = 1,
sRange = [0.4, 0.35],
Expand All @@ -33,7 +35,10 @@ export function generateHSLRamp({
return new Array(total).fill(0).map((_, i) => {
const relI = i / (total - 1);
return [
(360 + hStart + (1 - hEasing(relI, 1 / total)) * (360 * hCycles)) % 360,
(360 +
hStart +
(1 - hEasing(relI, 1 / total) - hStartCenter) * (360 * hCycles)) %
360,
sRange[0] + sDiff * sEasing(relI, 1 / total),
lRange[0] + lDiff * lEasing(relI, 1 / total),
];
Expand Down

0 comments on commit 8c34d90

Please sign in to comment.