├── old
├── README.md
├── doc
│ └── hydra-blending-modes.md
├── hydra-nowrap.js
└── hydra-blending-modes.js
├── doc
├── hydra-debug.md
├── hydra-vec4.md
├── hydra-swizzle.md
├── hydra-mouse.md
├── hydra-gif.md
├── hydra-fractals.md
├── hydra-wrap.md
├── hydra-tap.md
├── hydra-canvas.md
├── hydra-arrays.md
├── hydra-text.md
├── hydra-blend.md
├── hydra-outputs.md
├── hydra-arithmetics.md
├── ES
│ └── hydra-glsl.md
├── hydra-glsl.md
├── hydra-pixels.md
└── hydra-colorspaces.md
├── .github
└── FUNDING.yml
├── hydra-pip.js
├── hydra-canvas.js
├── hydra-pixels.js
├── hydra-mouse.js
├── hydra-arrays.js
├── utils
└── README.md
├── hydra-vec4.js
├── hydra-outputs.js
├── hydra-fractals.js
├── hydra-swizzle.js
├── hydra-gradientmap.js
├── hydra-tap.js
├── hydra-blend.js
├── hydra-src.js
├── hydra-text.js
├── hydra-debug.js
├── hydra-glsl.js
├── hydra-wrap.js
├── hydra-arithmetics.js
├── hydra-abbreviations.js
├── hydra-convolutions.js
├── README.md
└── hydra-colorspaces.js
/old/README.md:
--------------------------------------------------------------------------------
1 | # WARNING : deprecated
2 |
3 | Extensions in this folder are deprecated in favor of newer extensions.
4 |
5 | * hydra-blending-modes : use hydra-blend instead
6 | * hydra-nowrap : use hydra-wrap and set wrapping to nowrap instead
--------------------------------------------------------------------------------
/doc/hydra-debug.md:
--------------------------------------------------------------------------------
1 | # hydra-debug
2 |
3 | Adds tools to make it easier to debug sketches. As of now there's only one tool, but it's a useful one!
4 |
5 | ## Show fragment shader on screen
6 |
7 | ### .debug()
8 |
9 | `osc().debug()`
10 |
11 | The `debug` function will open a pop up inside Hydra showing the resulting fragment shader of any hydra texture.
12 |
13 | `osc().debug(output)`
14 |
15 | If you pass an output to the debug function, the pop up will be editable and will also have a `>` (run) button, allowing you to edit the fragment shader and re-run it. Note that the highlighting won't update until you press the `>` button.
--------------------------------------------------------------------------------
/doc/hydra-vec4.md:
--------------------------------------------------------------------------------
1 | # hydra-vec4
2 |
3 | Adds wrapper functions that allow you to construct vec4's like you would in GLSL.
4 |
5 | ## Overview
6 |
7 | This extension adds functions for `vec4`, `vec3` and `vec2`. `vec4` will return a `solid()` with the corresponding values, while `vec3` and `vec2` simply return arrays to be sent to the `vec4` function. However the extension takes into account if an array was created by a `vec`function, so you can still use arrays and functions as you would do normally in Hydra even as arguments to these new functions.
8 |
9 | ## Example
10 |
11 | ```js
12 | noise()
13 | .mult( vec4( vec3(0.5) , 1 ) )
14 | .add( vec4( [0.5,0].smooth() ) )
15 | .layer(
16 | vec4( vec3( [0, 1, 0.5] , vec2( ()=>time%1 ) ) , 1)
17 | .mask(shape(4))
18 | )
19 | .out()
20 | ```
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: geikha
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
14 |
--------------------------------------------------------------------------------
/doc/hydra-swizzle.md:
--------------------------------------------------------------------------------
1 | # hydra-swizzle
2 |
3 | This extensions replicates the [swizzling functionality from GLSL](https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)#Swizzling) in Hydra.
4 |
5 | ## Example
6 |
7 | ```js
8 | gradient(1).rbg
9 | .layer(osc(30,.1,2).bggr)
10 | .layer(gradient().r.mask(shape(2)))
11 | .out()
12 | ```
13 |
14 | ## Overview
15 |
16 | hydra-swizzle defines properties for each element in `rgba`and `xyzw`. As well for all possible combinations of `rgb`, `xyz`, `rgba` and `xyzw`. When you call only one element, It'll replicate itself to all channels except alpha. When you call 3 elements, It'll call them as expected and leave alpha as is. When you call 4 elements, they get assigned as you would expect.
17 |
18 | ```js
19 | texture().rgg // -> c0.rrga
20 | texture().bgba // -> c0.bgba
21 | texture().r // -> c0.rrra
22 | ```
23 |
--------------------------------------------------------------------------------
/doc/hydra-mouse.md:
--------------------------------------------------------------------------------
1 | # hydra-mouse
2 |
3 | This extension replaces the default mouse object used by Hydra, adding new properties.
4 |
5 | ---
6 |
7 | ## Properties
8 |
9 | ***Note:** In the next list, `mouse x y` means `mouse.x` and `mouse.y`*
10 |
11 | | properties | range / unit | relative to / absolute |
12 | |--------------------|------------------|------------------------|
13 | |`mouse x y` | pixels | browser's viewport |
14 | |`mouse ax ay` | pixels | absolute |
15 | |`mouse cx cy` | pixels | canvas (like p5) |
16 | |`mouse rx ry` | [0; 1] | browser's viewport |
17 | |`mouse crx cry` | [0; 1] | canvas |
18 | |`mouse posx posy` | [0.5; -0.5] | browser's viewport |
19 | |`mouse cposx cposy` | [0.5; -0.5] | canvas |
20 |
21 | ### Note
22 |
23 | You may wonder why is the range `[0.5; -0.5]` in an inverted order. This is because inside Hydra, scrolling by a positive number scrolls to the left or up, while scrolling by a negative one scrolls to the right or down.
--------------------------------------------------------------------------------
/doc/hydra-gif.md:
--------------------------------------------------------------------------------
1 | # hydra-gif
2 |
3 | Load `.gif` files to Hydra sources.
4 |
5 | ## Overview
6 |
7 | This extension uses [this GIF to canvas script](https://stackoverflow.com/questions/48234696/how-to-put-a-gif-with-canvas). This method has to completely uncompress the GIF so try to keep your GIFs light. Each source gets their own `.gif` property which allows you to change how the gif plays.
8 |
9 | ## Usage
10 |
11 | ### .initGif()
12 |
13 | `s0.initGif(url, delay, params)`
14 |
15 | Initialize a running GIF in the given source. `delay` allows you to set a delay in milliseconds from frame to frame, however this argument is optional and you can change it later. `params` is an object with properties for the regl texture that will act as the source, as the same with any other `.init` method.
16 |
17 | ### s0.gif
18 |
19 | `s0.gif`
20 |
21 | This is the object representing the gif, here are some of its useful properties:
22 |
23 | * `s0.gif.delay` : change the delay in milliseconds from frame to frame
24 | * `s0.gif.playSpeed` : change the play speed overall, you can set to negative values to go on reverse
25 | * `s0.gif.width`
26 | * `s0.gif.height`
--------------------------------------------------------------------------------
/old/doc/hydra-blending-modes.md:
--------------------------------------------------------------------------------
1 | # hydra-blending-modes
2 |
3 | ## **warning : deprecated !! use hydra-blend instead**
4 |
5 | Very simple but useful blending modes for Hydra. They all lack an intensity argument as of now.
6 | Taken from [hydra-blocky](https://github.com/samarthgulati/hydra-blockly/).
7 | Specifically [this file](https://github.com/samarthgulati/hydra-blockly/blob/master/image-editing-glsl-functions.js).
8 |
9 | See all available blending modes by evaluating:
10 |
11 | ```js
12 | > console.log(blendmodes_list)
13 | ```
14 |
15 | ```js
16 | {
17 | 0: "darken",
18 | 1: "multiply",
19 | 2: "colorBurn",
20 | 3: "linearBurn",
21 | 4: "darkerColor",
22 | 5: "lighten",
23 | 6: "screen",
24 | 7: "colorDodge",
25 | 8: "linearDodge",
26 | 9: "lighterColor",
27 | 10: "overlay",
28 | 11: "softLight",
29 | 12: "hardLight",
30 | 13: "vividLight",
31 | 14: "linearLight",
32 | 15: "pinLight",
33 | 16: "hardMix",
34 | 17: "difference",
35 | 18: "exclusion",
36 | 19: "subtract",
37 | 20: "divide",
38 | 21: "hueBlend",
39 | 22: "colorBlend",
40 | 23: "saturationBlend",
41 | 24: "luminosityBlend"
42 | }
43 | ```
44 |
--------------------------------------------------------------------------------
/hydra-pip.js:
--------------------------------------------------------------------------------
1 | {
2 | const getHydra = function () {
3 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
4 | ? "editor"
5 | : window.atom?.packages
6 | ? "atom"
7 | : "idk";
8 | if (whereami === "editor") {
9 | return window.hydraSynth;
10 | }
11 | if (whereami === "atom") {
12 | return global.atom.packages.loadedPackages["atom-hydra"]
13 | .mainModule.main.hydra;
14 | }
15 | let _h = [
16 | window.hydraSynth,
17 | window._hydra,
18 | window.hydra,
19 | window.h,
20 | window.H,
21 | window.hy
22 | ].find(h => h?.regl);
23 | return _h;
24 | };
25 | window._hydra = getHydra();
26 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
27 | }
28 |
29 | {
30 | const video = document.createElement("video"); video.autoplay = true;
31 | const canvas = _hydra.canvas;
32 | const stream = canvas.captureStream();
33 | video.srcObject = stream;
34 |
35 | window.hydraPip = ()=> video.requestPictureInPicture();
36 | window.hydraPictureInPicture = window.hydraPip;
37 | }
38 |
--------------------------------------------------------------------------------
/doc/hydra-fractals.md:
--------------------------------------------------------------------------------
1 | # hydra-fractals
2 |
3 | Adds mirroring and other functions that can be useful for making fractals. You should also check [`hydra-wrap`](./hydra-wrap.md) for fractals.
4 |
5 | ## Mirroring functions
6 |
7 | All mirroring functions are named after the axis which will be affected.
8 |
9 |
10 | ### mirrorX
11 |
12 | `.mirrorX( pos = 0 , coverage = 1 )`
13 |
14 | Result: `[1234|4321]`
15 |
16 | Leaves the image as is, up until `pos`, where it starts mirroring it. `coverage` is how long until the effect repeats itself. For example:
17 |
18 | `.mirrorX(0,0.5)`
19 |
20 | Result: `[12|21|12|21]`
21 |
22 | ### mirrorY
23 |
24 | `.mirrorY( pos = 0 , coverage = 1 )`
25 |
26 | Same as `mirrorX` but on the other axis.
27 |
28 | ### mirrorX2
29 |
30 | `.mirrorX2( pos = 0 , coverage = 1 )`
31 |
32 | Result: `[8765|5678]`
33 |
34 | Same as `mirrorX` but mirrors from the other side.
35 |
36 | ### mirrorY2
37 |
38 | `.mirrorY2( pos = 0 , coverage = 1 )`
39 |
40 | Same as `mirrorY` but mirrors from the other side.
41 |
42 | ### mirrorWrap
43 |
44 | `.mirrorWrap()`
45 |
46 | Will mirror any out of bounds coordinates. For example:
47 |
48 | Input: `[-8,-7,-6,-5,-4,-3,-2,-1] [1,2,3,4,5,6,7,8] [9,10,11,12,13,14,15,16]`
49 | Result: `[87654321] [12345678] [87654321]`
50 |
51 | ## Other functions
52 |
53 | ### inversion
54 |
55 | `.inversion()`
56 |
57 | Applies a circular inversion.
--------------------------------------------------------------------------------
/doc/hydra-wrap.md:
--------------------------------------------------------------------------------
1 | # hydra-wrap
2 |
3 | Allows you to change how Hydra wraps textures, and control the wrapping of generators.
4 |
5 | ## Overview
6 |
7 | This extensions works by changing all coordinate functions (such as `scrollX`, `scale`, etc) and setting them to not wrap at all. This change makes it so that generator functions (such as `osc`, `shape`, etc) don't wrap when you change their coordinates. As for textures (such as `s0`, `o0`), it lets you change the way they wrap (it may be `wrap`, `nowrap`, `mirror`). If you want a generator to wrap in the same way as textures do, you can simply write, for example, `osc().wrap()`.
8 |
9 | ---
10 |
11 | ## Functions
12 |
13 | You can access the different functions via the `hydraWrap` object.
14 |
15 | | Method | Description |
16 | |-------------------|----------------------------------------------------|
17 | | hydraWrap.setWrap() | Sets the wrapping on. This is the default. |
18 | | hydraWrap.setNoWrap() | Disables wrapping. This means textures will clamp. |
19 | | hydraWrap.setMirror() | Sets the wrapping to mirror. |
20 | | hydraWrap.setVoid() | Void does not actually change the wrapping method, but it means that **textures** won't render out of bounds coordinates instead of wrapping. You could use `hydra-src` with `hydraMask` instead. |
21 |
22 | As mentioned above, this extensions also adds a new coordinate function named `wrap` which will set any generator to wrap. See the following example:
23 |
24 | ```js
25 | shape().scale(.2).out(o0)
26 | shape().wrap().scale(.2).out(o1)
27 | render()
28 | ```
29 |
--------------------------------------------------------------------------------
/hydra-canvas.js:
--------------------------------------------------------------------------------
1 | {
2 | const getHydra = function () {
3 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
4 | ? "editor"
5 | : window.atom?.packages
6 | ? "atom"
7 | : "idk";
8 | if (whereami === "editor") {
9 | return window.hydraSynth;
10 | }
11 | if (whereami === "atom") {
12 | return global.atom.packages.loadedPackages["atom-hydra"]
13 | .mainModule.main.hydra;
14 | }
15 | let _h = [
16 | window.hydraSynth,
17 | window._hydra,
18 | window.hydra,
19 | window.h,
20 | window.H,
21 | window.hy
22 | ].find(h => h?.regl);
23 | return _h;
24 | };
25 | window._hydra = getHydra();
26 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
27 | }
28 |
29 | _hydraScope.canvas = window._hydra.canvas;
30 |
31 | _hydraScope.canvas.setLinear = function () {
32 | this.style.imageRendering = "auto";
33 | };
34 | _hydraScope.canvas.setNearest = function () {
35 | this.style.imageRendering = "pixelated";
36 | };
37 | _hydraScope.canvas.setFullscreen = function (full = true) {
38 | const set = full ? "100%" : "";
39 | this.style.width = set;
40 | this.style.height = set;
41 | };
42 | _hydraScope.canvas.setAlign = function (align = "right") {
43 | this.style.position = "relative";
44 | this.parentElement.style["text-align"] = align;
45 | };
46 | _hydraScope.canvas.setRelativeSize = function (ratio) {
47 | this.style.width = "" + width * ratio + "px";
48 | this.style.height = "" + height * ratio + "px";
49 | };
50 |
--------------------------------------------------------------------------------
/doc/hydra-tap.md:
--------------------------------------------------------------------------------
1 | # hydra-tap
2 |
3 | A tap bpm control for Hydra. Inspired by Resolume's own tap.
4 |
5 | ## Example
6 |
7 | ```js
8 | osc(30,.01,beats(1)).out()
9 |
10 | osc().rotate(beats_(2).curve(-3)).out()
11 |
12 | osc().scale(beats(1).curve(2).range(1,2)).out()
13 |
14 | // Ctrl + Space Bar for tapping
15 | // Ctrl + , (Comma) for re-sync
16 | ```
17 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlkcmEtZXh0ZW5zaW9ucy5nbGl0Y2gubWUlMkZoeWRyYS10YXAuanMlMjIpJTBBJTBBb3NjKDMwJTJDLjAxJTJDYmVhdHMoMSkpLm91dCgpJTBBJTBBb3NjKCkucm90YXRlKGJlYXRzXygyKS5jdXJ2ZSgtMykpLm91dCgpJTBBJTBBb3NjKCkuc2NhbGUoYmVhdHMoMSkuY3VydmUoMikucmFuZ2UoMSUyQzIpKS5vdXQoKSUwQSUwQSUyRiUyRiUyMEN0cmwlMjAlMkIlMjBTcGFjZSUyMEJhciUyMGZvciUyMHRhcHBpbmclMEElMkYlMkYlMjBDdHJsJTIwJTJCJTIwJTJDJTIwKENvbW1hKSUyMGZvciUyMHJlLXN5bmM%3D)
18 |
19 | ## Usage
20 |
21 | ### Tap
22 |
23 | * `Ctrl + Space Bar` for tapping.
24 | * `Ctrl + , (Comma)` for re-sync (resets time to 0).
25 |
26 | ### Envelopes
27 |
28 | * `beats(n=1)`: A linear ramp from 1 down to 0 every `n` beats
29 | * `beats_(n=1)`: A linear ramp from 0 up to 1 every `n` beats
30 | * `beatsTri(n=1)`: Goes from 1 to 0 on `n` beats, and then back to 1 in the same time, creating a triangle wave.
31 | * `beatsTri_(n=1)`: Same as avobe but inverted.
32 |
33 | #### Curve
34 |
35 | You can seat the curve of a beat envelope by calling `.curve(q)` on it. Positive values will ease in and negative values will ease out. For example, `beats().curve(3)` would be cubic easing in.
36 |
37 | #### Range
38 |
39 | You can also set the range for an envelope or a curved envelope by calling `.range(min=0,max=1)` on it. For example: `osc().scale(beatsTri(2).curve(2).range(1,2))`.
--------------------------------------------------------------------------------
/hydra-pixels.js:
--------------------------------------------------------------------------------
1 | //hydra-pixels
2 | //read pixels from each hydra output
3 |
4 | {
5 | const getHydra = function () {
6 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
7 | ? "editor"
8 | : window.atom?.packages
9 | ? "atom"
10 | : "idk";
11 | if (whereami === "editor") {
12 | return window.hydraSynth;
13 | }
14 | if (whereami === "atom") {
15 | return global.atom.packages.loadedPackages["atom-hydra"]
16 | .mainModule.main.hydra;
17 | }
18 | let _h = [
19 | window.hydraSynth,
20 | window._hydra,
21 | window.hydra,
22 | window.h,
23 | window.H,
24 | window.hy
25 | ].find(h => h?.regl);
26 | return _h;
27 | };
28 | window._hydra = getHydra();
29 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
30 | }
31 |
32 | {
33 | const oP = _hydra.o[0].constructor.prototype;
34 |
35 | const regl = _hydra.o[0].regl;
36 | regl.attributes.preserveDrawingBuffer = true;
37 | oP.read = function (x = 0, y = 0, w = 1, h = 1) {
38 | return regl.read({
39 | framebuffer: this.fbos[this.pingPongIndex],
40 | x: x,
41 | y: y,
42 | width: w,
43 | height: h,
44 | });
45 | };
46 | oP.readAll = function () {
47 | const fbo = this.fbos[this.pingPongIndex];
48 | return regl.read({
49 | framebuffer: fbo,
50 | x: 0,
51 | y: 0,
52 | width: fbo.width,
53 | height: fbo.height,
54 | });
55 | };
56 | }
57 |
--------------------------------------------------------------------------------
/doc/hydra-canvas.md:
--------------------------------------------------------------------------------
1 | # hydra-canvas
2 |
3 | This extension provides several methods for modifying the appearance and behavior of a canvas element in a web page.
4 |
5 | ## The canvas object
6 |
7 | canvas: A reference to the canvas element with a class of bg-black. This makes this extension only work within the hydra editor.
8 |
9 | ## Methods
10 |
11 | ### `setLinear()`
12 |
13 | Sets the imageRendering property of the canvas element to auto, which causes the browser to use a linear interpolation algorithm for scaling the image.
14 |
15 | ### `setNearest()`
16 |
17 | Sets the imageRendering property of the canvas element to pixelated, which causes the browser to use nearest neighbor interpolation for scaling the image. This results in a pixelated appearance when the canvas is scaled.
18 |
19 | ### `setFullscreen(full=true)`
20 |
21 | Sets the width and height of the canvas element to 100% if full is true, or an empty string if full is false. This causes the canvas to fill the available space in the parent element.
22 |
23 | ### `setAlign(align='right')`
24 |
25 | Sets the text-align property of the parent element of the canvas element to the specified value. The default value is 'right'.
26 |
27 | ### `setRelativeSize(ratio)`
28 |
29 | Sets the width and height of the canvas element to a specified ratio of the current width and height.
30 |
31 | ## Examples
32 |
33 | ```javascript
34 | // Set the canvas to fill the available space in the parent element
35 | canvas.setFullscreen();
36 |
37 | // Set the canvas to use nearest neighbor interpolation for scaling
38 | canvas.setNearest();
39 |
40 | // Set the canvas to be 50% of its current size
41 | canvas.setRelativeSize(0.5);
42 |
43 | // Set the parent element of the canvas to align its contents to the left
44 | canvas.setAlign('left');
45 | ```
46 |
--------------------------------------------------------------------------------
/doc/hydra-arrays.md:
--------------------------------------------------------------------------------
1 | # hydra-arrays
2 |
3 | Extends the functionality of arrays in Hydra, letting you operate between different arrays and generate new ones.
4 |
5 | ## Operators
6 |
7 | ### Regular operators
8 |
9 | `.add`, `.sub`, `.mult`, `.div`, `.mod`
10 |
11 | These will let you add either a constant or an array to another array. If the second array is smaller than the first one, it simply stops there. For example:
12 |
13 | ```
14 | [0,1,2,3].add(1) == [1,2,3,4]
15 | [0,1,2,3].add([1,2]) == [1,3,2,3]
16 | ```
17 |
18 | ### Wrap operators
19 |
20 | `.addWrap`, `.subWrap`, `.multWrap`, `.divWrap`, `.modWrap`
21 |
22 | These are just like the regular operators, but if the second array is smaller than the first one, it'll repeat itself until going through every single element in the first array.
23 |
24 | ```
25 | [0,1,2,3].add([1,2]) == [1,3,2,3]
26 | [0,1,2,3].addWrap([1,2]) == [1,3,3,5]
27 | ```
28 |
29 | ## Methods
30 |
31 | ### shuffle
32 |
33 | `.shuffle()`
34 |
35 | Will return a shuffled version of any array.
36 |
37 | ### zfill
38 |
39 | `.zfill(length, z = 0)`
40 |
41 | Will concat `z` to the array repeatedly until the array reaches the desired length. Inspired by python's zfill, however, the one shown here adds the zeroes at the end of the array.
42 |
43 | ### rotate
44 |
45 | `.rotate(n)` / `.rot(n)`
46 |
47 | Will rotate the array by `n` steps. Works with negative values.
48 |
49 | ## Generators
50 |
51 | ### Array.random
52 |
53 | `Array.random(length = 10, min = 0, max = 1)`
54 |
55 | Generates a new array of a given length and fills it with random values between the range `min` to `max`.
56 |
57 | ### Array.range
58 |
59 | `Array.range(start, end, step = 1)`
60 |
61 | Generates a new array of numbers starting from `start`, then each element increases by `step` until `end` (non-inclusive).
62 |
63 | ### Array.run
64 |
65 | `Array.range(end = 10, step = 1)`
66 |
67 | Generates a new array of numbers starting from 0, then each element increses by `step` until `end` (non-inclusive).
--------------------------------------------------------------------------------
/doc/hydra-text.md:
--------------------------------------------------------------------------------
1 | # hydra-text
2 |
3 | A text source for Hydra
4 |
5 | ## hydraText
6 |
7 | `hydraText` are the default settings for hydra-text, which you can change:
8 |
9 | ```js
10 | hydraText.font = "serif";
11 |
12 | // these are the defaults:
13 | window.hydraText = {
14 | font: "sans-serif", // the font-family
15 | fontStyle: "normal", // normal, bold, etc
16 | fontSize: "auto", // must be either "auto", a percentage like "90%", or pixels like "100px"
17 | textAlign: "center", // center, left or right
18 | fillStyle: "white", // a css color, CanvasGradient or CanvasPattern
19 | strokeStyle: "white", // a css color, CanvasGradient or CanvasPattern
20 | lineWidth: "2%", // a percentage of the final fontSize
21 | lineJoin: "miter", // miter, bevel or round
22 | canvasResize: 2, // a factor by which to resize the canvas that displays the text
23 | interpolation: "linear",// linear or nearest. represents the interpolation used inside hydra for the text's canvas
24 | };
25 | ```
26 |
27 | Settings are set to a CanvasRenderingContext2D, find more about it [here](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle). However note that the hydra-text `font` setting doesn't work the same as the context's `font` property. On hydra-text, `font` should only specify the font-family. This is because it needs to do some resizing and measurements of the text before writing it while the context's `font` property allows you to resize it.
28 |
29 | ## text
30 |
31 | `text( str, config )`
32 |
33 | * str: the text you want to write
34 | * config: either an object with the properties you want to set, or a string with the font you want
35 |
36 | ## strokeText
37 |
38 | `strokeText( str, config )`
39 |
40 | Same as `text` but draws the outline of the text instead
41 |
42 | ## strokeFillText
43 |
44 | `strokeFillText( str, config )`
45 |
46 | Fill over stroke
47 |
48 | ## fillStrokeText
49 |
50 | `fillStrokeText( str, config )`
51 |
52 | Stroke over fill
--------------------------------------------------------------------------------
/doc/hydra-blend.md:
--------------------------------------------------------------------------------
1 | # hydra-blend
2 |
3 | A port of [glsl-blend](https://github.com/jamieowen/glsl-blend) to Hydra.
4 |
5 | ## Overview
6 |
7 | This extension adds most of the blending modes that you see on raster image software to Hydra. You should use them with the following syntax: `tex.blendModeName(tex2, opacity)`, where tex and tex2 are any two Hydra textures and opacity is a number (or array or function as in regular Hydra).
8 |
9 | Please read the [disclaimer about alpha here below](#important)
10 |
11 | ## List of blending modes
12 |
13 | * darken
14 | * multiply
15 | * colorBurn
16 | * linearBurn
17 | * lighten
18 | * screen
19 | * colorDodge
20 | * linearDodge
21 | * overlay
22 | * softLight
23 | * hardLight
24 | * vividLight
25 | * linearLight
26 | * pinLight
27 | * hardMix
28 | * difference
29 | * exclusion
30 | * subtract
31 | * divide
32 | * negation / negate
33 | * add2 (i didn't want to replace the regular Hydra `add`)
34 | * glow
35 | * reflect
36 | * phoenix
37 |
38 | ## About the alpha channel
39 |
40 | `glsl-blend` doesn't have any functions that work with RGBA, all function work with opaque textures of RGB. After lots of playing around with Photopea I realized that what most raster image softwares do is apply the blending over premultiplied sources and then, wherever the base texture is transparent, layer over the texture to be blended, and that's how I implemented it
41 |
42 | ### Important
43 |
44 | This extension overwrites Hydra's `layer`, `luma` and `mask` in order for them to stricly use premultiplied alpha. This means that if something doesn't look as expected, it's probably because the textures you're using aren't premultiplied and in a range from 0.0 to 1.0. `noise` will surely give you problems as it ranges from -1 to 1.
45 |
46 | I could've handled this inside the blending modes but I didn't want to taker over your ability to purposefully glitch stuff. If something doesn't look as you expect it to look you can try to premultiply it by doing `tex.premultiply()` alias `tex.pm()`. It's a function I've added that will take care of any overloaded or mismatched values.
47 |
48 | ### Note
49 |
50 | If you're interested in alpha compositing inside Hydra, please join the discussion [here](https://github.com/hydra-synth/hydra-synth/issues/109)
--------------------------------------------------------------------------------
/hydra-mouse.js:
--------------------------------------------------------------------------------
1 | {
2 | const getHydra = function () {
3 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
4 | ? "editor"
5 | : window.atom?.packages
6 | ? "atom"
7 | : "idk";
8 | if (whereami === "editor") {
9 | return window.hydraSynth;
10 | }
11 | if (whereami === "atom") {
12 | return global.atom.packages.loadedPackages["atom-hydra"]
13 | .mainModule.main.hydra;
14 | }
15 | let _h = [
16 | window.hydraSynth,
17 | window._hydra,
18 | window.hydra,
19 | window.h,
20 | window.H,
21 | window.hy
22 | ].find(h => h?.regl);
23 | return _h;
24 | };
25 | window._hydra = getHydra();
26 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
27 | }
28 |
29 | function Mouse(canvas) {
30 | this.x = 0;
31 | this.y = 0;
32 | this.ax = 0;
33 | this.ay = 0;
34 | this.cx = 0;
35 | this.cy = 0;
36 | this.rx = 0;
37 | this.ry = 0;
38 | this.crx = 0;
39 | this.cry = 0;
40 | this.posx = 0;
41 | this.posy = 0;
42 | this.cposx = 0;
43 | this.cposy = 0;
44 | this.canvas = canvas;
45 | let self = this;
46 |
47 | this.handlePointerMove = function (ev) {
48 | const bound = self.canvas.getBoundingClientRect();
49 | self.x = ev.clientX;
50 | self.y = ev.clientY;
51 | self.ax = ev.pageX;
52 | self.ay = ev.pageY;
53 | self.cx = self.ax - bound.left;
54 | self.cy = self.ay - bound.top;
55 | self.rx = self.x / window.innerWidth;
56 | self.ry = self.y / window.innerHeight;
57 | self.crx = self.cx / bound.width;
58 | self.cry = self.cy / bound.height;
59 | self.posx = -self.x / window.innerWidth + 0.5;
60 | self.posy = -self.y / window.innerHeight + 0.5;
61 | self.cposx = -self.cx / bound.width + 0.5;
62 | self.cposy = -self.cy / bound.height + 0.5;
63 | };
64 |
65 | if (window.mouse.handlePointerMove)
66 | window.removeEventListener(
67 | "pointermove",
68 | window.mouse.handlePointerMove
69 | );
70 | window.addEventListener("pointermove", this.handlePointerMove);
71 | }
72 |
73 | _hydraScope.mouse = new Mouse(window._hydra.canvas);
74 |
--------------------------------------------------------------------------------
/hydra-arrays.js:
--------------------------------------------------------------------------------
1 | window.hydraArrays = {};
2 |
3 | hydraArrays.newOperator = function (self, f) {
4 | return function (arr) {
5 | for (let i = 0; i < self.length; i++) {
6 | if (Array.isArray(arr)) {
7 | self[i] = arr[i] ? f(self[i], arr[i]) : self[i];
8 | } else {
9 | self[i] = f(self[i], arr);
10 | }
11 | }
12 | return self;
13 | };
14 | };
15 | hydraArrays.newWrapOperator = function (self, f) {
16 | return function (arr) {
17 | for (let i = 0; i < self.length; i++) {
18 | if (Array.isArray(arr)) {
19 | self[i] = f(self[i], arr[i % arr.length]);
20 | } else {
21 | self[i] = f(self[i], arr);
22 | }
23 | }
24 | return self;
25 | };
26 | };
27 |
28 | // operators
29 | {
30 | const operators = {
31 | add: (x, y) => x + y,
32 | sub: (x, y) => x - y,
33 | div: (x, y) => x / y,
34 | mult: (x, y) => x * y,
35 | mod: (x, y) => x % y,
36 | };
37 | Object.entries(operators).forEach(function ([op, f]) {
38 | Array.prototype[op] = function (arr) {
39 | return hydraArrays.newOperator(this, f)(arr);
40 | };
41 | Array.prototype[op + "Wrap"] = function (arr) {
42 | return hydraArrays.newWrapOperator(this, f)(arr);
43 | };
44 | });
45 | }
46 |
47 | // methods
48 | Array.prototype.shuffle = function () {
49 | return this.sort(() => Math.random() - 0.5);
50 | };
51 | Array.prototype.zfill = function (l, z = 0) {
52 | const _l = this.length;
53 | for (let i = 0; i < l - _l; i++) this.push(z);
54 | return this;
55 | };
56 | Array.prototype.rotate = function (n) {
57 | const len = this.length;
58 | this.push(...this.splice(0, ((-n % len) + len) % len));
59 | return this;
60 | };
61 | Array.prototype.rot = Array.prototype.rotate;
62 |
63 | // generators
64 | Array.random = function (l = 10, min = 0, max = 1) {
65 | return Array.from(
66 | { length: l },
67 | () => Math.random() * (max - min) + min
68 | );
69 | };
70 | Array.range = function (start, end, step = 1) {
71 | if (step === 0) return [];
72 | const length = Math.ceil((end - start) / step);
73 | return Array.from({ length }, (_, i) => start + i * step).filter(
74 | (n) => n <= end
75 | );
76 | };
77 | Array.run = function (end = 10, step = 1) {
78 | return Array.range(0, end, step);
79 | };
80 |
--------------------------------------------------------------------------------
/doc/hydra-outputs.md:
--------------------------------------------------------------------------------
1 | # hydra-outputs
2 |
3 | Allows users to change the settings of the framebuffers used by Hydra's outputs. The most common use case is setting framebuffers to use linear interpolation instead of the default, nearest neighbour.
4 |
5 | ### Example
6 |
7 | ```js
8 | o0.setNearest()
9 | o1.setLinear()
10 |
11 | src(o0)
12 | .layer(osc(30,.2,1).mask(shape(4,.1,0)))
13 | .scale(1.01).rotate(.01)
14 | .out(o0)
15 |
16 | src(o1)
17 | .layer(osc(30,.2,1).mask(shape(4,.1,0)))
18 | .scale(1.01).rotate(.01)
19 | .out(o1)
20 |
21 | src(o0)
22 | .layer(src(o1).mask(shape(1,0,0).rotate(Math.PI/2)))
23 | .out(o2)
24 |
25 | render(o2)
26 | ```
27 |
28 | [Open in Hydra!](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtb3V0cHV0cy5qcyUyMiklMEElMEFvMC5zZXROZWFyZXN0KCklMEFvMS5zZXRMaW5lYXIoKSUwQSUwQXNyYyhvMCklMEElMDkubGF5ZXIob3NjKDMwJTJDLjIlMkMxKS5tYXNrKHNoYXBlKDQlMkMuMSUyQzApKSklMEElMDkuc2NhbGUoMS4wMSkucm90YXRlKC4wMSklMEElMDkub3V0KG8wKSUwQSUwQXNyYyhvMSklMEElMDkubGF5ZXIob3NjKDMwJTJDLjIlMkMxKS5tYXNrKHNoYXBlKDQlMkMuMSUyQzApKSklMEElMDkuc2NhbGUoMS4wMSkucm90YXRlKC4wMSklMEElMDkub3V0KG8xKSUwQSUwQXNyYyhvMCklMEElMDkubGF5ZXIoc3JjKG8xKS5tYXNrKHNoYXBlKDElMkMwJTJDMCkucm90YXRlKE1hdGguUEklMkYyKSkpJTBBJTA5Lm91dChvMiklMEElMEFyZW5kZXIobzIp)
29 |
30 | ---
31 |
32 | ## How to use
33 |
34 | This extensions extends the `Output` prototype, so it adds methods to all outputs such as `o0`, `o1`, etc. It also adds a new `oS` object, which lets you use these methods on all outputs at the same time.
35 |
36 | ### Methods
37 |
38 | | Method | Description |
39 | |---|---|
40 | | o0.setLinear() | Sets the interpolation method to linear. Looks smooth. |
41 | | o0.setNearest()| Sets the interpolation method to nearest neighbour. Looks pixelated. |
42 | | o0.setFbos(fbo0, fbo1) | Lets you set any of [the texture properties regl allows](https://github.com/regl-project/regl/blob/master/API.md#texture-constructor). If you only set fbo0, fbo1 will copy those settings. |
43 |
44 | * Remember you can change all outputs at the same time as such: `oS.setLinear()`
45 | * You may want to use setFbos to set different interpolation methods for `mag` and `min`. For example: `oS.setFbos({ mag: 'linear', min: 'nearest' })`
46 |
47 | #### Wrapping methods
48 |
49 | If you want to change Hydra's wrapping mode I'd recommend using hydra-wrap. But if you're sure that what you want to do is change the fbos wrapping settings you may also use the following methods.
50 |
51 | | Method | Description |
52 | |---|---|
53 | | o0.setRepeat() | Sets the wrapping to repeat |
54 | | o0.setMirror() | Sets the wrapping to mirror |
55 | | o0.setClamp() | Sets the wrapping to clamp |
56 |
--------------------------------------------------------------------------------
/utils/README.md:
--------------------------------------------------------------------------------
1 | # utility scripts
2 |
3 | These are some scripts I've come up with to have some sort of framework to make the extensions compatible with most scenarios and between each other:
4 |
5 | ## Find the HydraRenderer object
6 |
7 | Finds hydra and assigns it to `window._hydra`. Will also get the scope of the generator functions and assign it to `window._hydraScope` so that you can code extensions compatible with instance mode. All following scripts depend on this one to be run first.
8 |
9 | ```js
10 | {
11 | const getHydra = function () {
12 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
13 | ? "editor"
14 | : window.atom?.packages
15 | ? "atom"
16 | : "idk";
17 | if (whereami === "editor") {
18 | return window.hydraSynth;
19 | }
20 | if (whereami === "atom") {
21 | return global.atom.packages.loadedPackages["atom-hydra"]
22 | .mainModule.main.hydra;
23 | }
24 | let _h = [
25 | window.hydraSynth,
26 | window._hydra,
27 | window.hydra,
28 | window.h,
29 | window.H,
30 | window.hy
31 | ].find(h => h?.regl);
32 | return _h;
33 | };
34 | window._hydra = getHydra();
35 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
36 | }
37 | ```
38 |
39 | Tip: Always call `setFunction` from `_hydra.synth.setFunction`
40 |
41 | ## Get prototypes
42 |
43 | ```js
44 | const gS = _hydraScope.osc().constructor.prototype; // GlslSource prototype
45 | const oP = _hydra.o[0].constructor.prototype; // Output prototype
46 | const hS = _hydra.s[0].constructor.prototype; // HydraSource prototype
47 | ```
48 |
49 | ## Custom update chain
50 |
51 | The following script unlinks the reference from `window.update` to `_hydra.synth.update`, replacing it with another placeholder. It then defines a `_updateChain` array of functions which will then be ran by the actual `_hydra.synth.update`. This allows you to inject new functions into the hydra tick loop via pushing to them the `_updateChain` array. Take into account other extensions might also push, so always keep track of your function's indexes in the array yourself.
52 |
53 | ```js
54 | {
55 | if (!window._updateChain) {
56 | window.update = window.update || ((dt) => { });
57 | window._updateChain = [() => window["update"]()];
58 | _hydra.sandbox.userProps = ["speed", "bpm", "fps"];
59 | _hydra.synth.update = (dt) => {
60 | for (func of window._updateChain) {
61 | func(dt);
62 | }
63 | };
64 | }
65 | }
66 | ```
67 |
--------------------------------------------------------------------------------
/hydra-vec4.js:
--------------------------------------------------------------------------------
1 | {
2 | const getHydra = function () {
3 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
4 | ? "editor"
5 | : window.atom?.packages
6 | ? "atom"
7 | : "idk";
8 | if (whereami === "editor") {
9 | return window.hydraSynth;
10 | }
11 | if (whereami === "atom") {
12 | return global.atom.packages.loadedPackages["atom-hydra"]
13 | .mainModule.main.hydra;
14 | }
15 | let _h = [
16 | window.hydraSynth,
17 | window._hydra,
18 | window.hydra,
19 | window.h,
20 | window.H,
21 | window.hy
22 | ].find(h => h?.regl);
23 | return _h;
24 | };
25 | window._hydra = getHydra();
26 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
27 | }
28 |
29 | {
30 | function filterVecArgs(args) {
31 | let pass = [];
32 | args.forEach((arg) => {
33 | if (typeof arg == "number" || typeof arg == "function")
34 | pass = pass.concat(arg);
35 | else if (arg.constructor.name == "Array") {
36 | if (arg._vec) pass = pass.concat(arg);
37 | else pass = pass.concat([arg]);
38 | }
39 | });
40 | return pass;
41 | }
42 | window.vec4 = function (...args) {
43 | args = filterVecArgs(args);
44 | if (args.length == 1) {
45 | const arg = args[0];
46 | return solid(arg, arg, arg, arg);
47 | } else if (args.length == 4) {
48 | return _hydraScope.solid(...args);
49 | } else {
50 | throw new Error("vec4 should receive 4 elements");
51 | }
52 | };
53 | window.vec3 = function (...args) {
54 | args = filterVecArgs(args);
55 | if (args.length == 1) {
56 | const arg = args[0];
57 | let ret = Array.from({ length: 3 }, () => arg);
58 | ret._vec = true;
59 | return ret;
60 | } else if (args.length == 3) {
61 | args._vec = true;
62 | return args;
63 | } else {
64 | throw new Error("vec3 should receive 3 elements");
65 | }
66 | };
67 | window.vec2 = function (...args) {
68 | args = filterVecArgs(args);
69 | if (args.length == 1) {
70 | const arg = args[0];
71 | let ret = Array.from({ length: 2 }, () => arg);
72 | ret._vec = true;
73 | return ret;
74 | } else if (args.length == 2) {
75 | args._vec = true;
76 | return args;
77 | } else {
78 | throw new Error("vec2 should receive 2 elements");
79 | }
80 | };
81 | }
82 |
--------------------------------------------------------------------------------
/hydra-outputs.js:
--------------------------------------------------------------------------------
1 | {
2 | const getHydra = function () {
3 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
4 | ? "editor"
5 | : window.atom?.packages
6 | ? "atom"
7 | : "idk";
8 | if (whereami === "editor") {
9 | return window.hydraSynth;
10 | }
11 | if (whereami === "atom") {
12 | return global.atom.packages.loadedPackages["atom-hydra"]
13 | .mainModule.main.hydra;
14 | }
15 | let _h = [
16 | window.hydraSynth,
17 | window._hydra,
18 | window.hydra,
19 | window.h,
20 | window.H,
21 | window.hy
22 | ].find(h => h?.regl);
23 | return _h;
24 | };
25 | window._hydra = getHydra();
26 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
27 | }
28 |
29 | {
30 | const oP = _hydra.o[0].constructor.prototype;
31 | oP.fboSettings = Array(2).fill({
32 | mag: "nearest",
33 | min: "nearest",
34 | width: width,
35 | height: height,
36 | format: "rgba",
37 | });
38 | oP.setFbos = function (fbo0, fbo1) {
39 | var colors = fbo1 ? [fbo0, fbo1] : [fbo0, fbo0];
40 | this.fboSettings = colors.map((x, i) => {
41 | return {
42 | ...this.fboSettings[i],
43 | width: width,
44 | height: height,
45 | ...x,
46 | };
47 | });
48 | this.fbos = this.fboSettings.map((x) =>
49 | this.regl.framebuffer({
50 | color: this.regl.texture(x),
51 | depthStencil: false,
52 | })
53 | );
54 | };
55 | oP.setNearest = function () {
56 | this.setFbos({ mag: "nearest", min: "nearest" });
57 | };
58 | oP.setLinear = function () {
59 | this.setFbos({ mag: "linear", min: "linear" });
60 | };
61 | oP.setRepeat = function () {
62 | this.setFbos({ wrapS: "repeat", wrapT: "repeat" });
63 | };
64 | oP.setClamp = function () {
65 | this.setFbos({ wrapS: "clamp", wrapT: "clamp" });
66 | };
67 | oP.setMirror = function () {
68 | this.setFbos({ wrapS: "mirror", wrapT: "mirror" });
69 | };
70 | _hydraScope.oS = { outputs: window._hydra.o };
71 | _hydraScope.oS.setNearest = function () {
72 | this.outputs.forEach((x) => x.setNearest());
73 | };
74 | _hydraScope.oS.setLinear = function () {
75 | this.outputs.forEach((x) => x.setLinear());
76 | };
77 | _hydraScope.oS.setRepeat = function () {
78 | this.outputs.forEach((x) => x.setWrap());
79 | };
80 | _hydraScope.oS.setClamp = function () {
81 | this.outputs.forEach((x) => x.setClamp());
82 | };
83 | _hydraScope.oS.setMirror = function () {
84 | this.outputs.forEach((x) => x.setMirror());
85 | };
86 | _hydraScope.oS.setFbos = function (_x, y) {
87 | this.outputs.forEach((x) => x.setFbos(_x, y));
88 | };
89 | }
90 |
--------------------------------------------------------------------------------
/doc/hydra-arithmetics.md:
--------------------------------------------------------------------------------
1 | # hydra-arithmetics
2 |
3 | Adds many functions related to visual arithmetics.
4 |
5 | ## Operators
6 |
7 | All operators in this extension are actually wrappers that let you operate by either a number (or array or function as with regular hydra) or a texture. This basically means you can both do `osc().add(noise())` or `osc().add(1)` and both will work as expected.
8 |
9 | ### div
10 |
11 | `.div( divisor )`
12 |
13 | Divide a texture by some value or texture
14 |
15 | ### add, sub, mult
16 |
17 | | single value | texture |
18 | |----------------|------------------------|
19 | |`.add( value )` | `.add( tex , amount )` |
20 | |`.sub( value )` | `.sub( tex , amount )` |
21 | |`.mult( value )`| `.mult( tex , amount )`|
22 |
23 | These act the same as in regular Hydra, with the added functionality of working with regular values too.
24 |
25 | ### mod
26 |
27 | `.mod( x )`
28 |
29 | Calculates the modulo `x` for the texture that calls it.
30 |
31 | ### min, max
32 |
33 | `.min( x )`, `.max( x )`
34 |
35 | Returns the minimum or maximum value when compared to the texture that calls it, accordingly.
36 |
37 | ### step
38 |
39 | `.step( x )`
40 |
41 | Generates a step function by comparing x to the texture that calls it.
42 |
43 | ### amp, offset
44 |
45 | `.amp( singleValue ) == .amplitude( singleValue )`, `.offset( singleValue ) == .off( singleValue )`
46 |
47 | These are basically aliases for `.mult()` and `.add()` for single values.
48 |
49 | ---
50 |
51 | ## Bipolar and unipolar
52 |
53 | ### bipolar
54 |
55 | `.bipolar( amp = 1 )`
56 |
57 | Takes unipolar values (values ranged from 0 to 1) and turns them to bipolar (ranged from -1 to 1). The `amp` argument let's you multiply the result by some value if needed.
58 |
59 | ### unipolar
60 |
61 | `.unipolar( amp = 1 )`
62 |
63 | Takes bipolar values (-1 to 1) and turns them to unipolar (0 to 1). The `amp` argument let's you multiply the result by some value if needed.
64 |
65 | ---
66 |
67 | ## Ranges
68 |
69 | ### range
70 |
71 | `.range( min = 0, max = 1 )`
72 |
73 | Allows you to change the range the range of unipolar values to one between `min` and `max`.
74 |
75 | ### birange
76 |
77 | `.birange( min = 0, max = 1 )`
78 |
79 | Allows you to change the range the range of bipolar values to one between `min` and `max`.
80 |
81 | ### clamp
82 |
83 | `.clamp( min = 0, max = 1 )`
84 |
85 | `clamp` will constrain values between a range from `min` to `max`.
86 |
87 | ---
88 |
89 | ## Other transformations
90 |
91 | This extension also adds many argument-less transforms. You can use them as such, for example: `osc().abs()`.
92 |
93 | ### abs, fract, sign
94 |
95 | #### abs
96 |
97 | Returns the absolute value.
98 |
99 | #### fract
100 |
101 | Returns only the fractional part of a value.
102 |
103 | #### sign
104 |
105 | Sign function, will return 1 for positive values and -1 for negative values.
106 |
107 | ### Trigonometic functions
108 |
109 | The following are included: `sin`, `cos`, `tan`, `asin`, `acos`, `atan`
110 |
111 | ### Exponential and rational functions
112 |
113 | The following are included: `exp`, `log`, `exp2`, `log2`, `sqrt`, `inversesqrt`
--------------------------------------------------------------------------------
/old/hydra-nowrap.js:
--------------------------------------------------------------------------------
1 | const fboSettings = Array(2).fill({
2 | mag: "nearest",
3 | min: "nearest",
4 | width: width,
5 | height: height,
6 | wrapS: 'clamp',
7 | wrapT: 'clamp',
8 | format: "rgba"
9 | });
10 | choo.state.hydra.hydra.o.forEach((output) => {
11 | output.fbos = fboSettings.map((x) =>
12 | output.regl.framebuffer({
13 | color: output.regl.texture(x),
14 | depthStencil: false,
15 | })
16 | );
17 | });
18 |
19 | [
20 | {
21 | name: "prev",
22 | type: "src",
23 | inputs: [],
24 | glsl: `return texture2D(prevBuffer, _st);`,
25 | },
26 | {
27 | name: "src",
28 | type: "src",
29 | inputs: [
30 | {
31 | type: "sampler2D",
32 | name: "tex",
33 | default: NaN,
34 | },
35 | ],
36 | glsl: `return texture2D(tex, _st);`,
37 | },
38 | {
39 | name: "scroll",
40 | type: "coord",
41 | inputs: [
42 | {
43 | type: "float",
44 | name: "scrollX",
45 | default: 0.5,
46 | },
47 | {
48 | type: "float",
49 | name: "scrollY",
50 | default: 0.5,
51 | },
52 | {
53 | type: "float",
54 | name: "speedX",
55 | default: 0,
56 | },
57 | {
58 | type: "float",
59 | name: "speedY",
60 | default: 0,
61 | },
62 | ],
63 | glsl: `_st.x += scrollX + time*speedX; _st.y += scrollY + time*speedY; return _st;`,
64 | },
65 | {
66 | name: "scrollX",
67 | type: "coord",
68 | inputs: [
69 | {
70 | type: "float",
71 | name: "scrollX",
72 | default: 0.5,
73 | },
74 | {
75 | type: "float",
76 | name: "speed",
77 | default: 0,
78 | },
79 | ],
80 | glsl: `_st.x += scrollX + time*speed; return _st;`,
81 | },
82 | {
83 | name: "modulateScrollX",
84 | type: "combineCoord",
85 | inputs: [
86 | {
87 | type: "float",
88 | name: "scrollX",
89 | default: 0.5,
90 | },
91 | {
92 | type: "float",
93 | name: "speed",
94 | default: 0,
95 | },
96 | ],
97 | glsl: `_st.x += _c0.r*scrollX + time*speed; return _st;`,
98 | },
99 | {
100 | name: "scrollY",
101 | type: "coord",
102 | inputs: [
103 | {
104 | type: "float",
105 | name: "scrollY",
106 | default: 0.5,
107 | },
108 | {
109 | type: "float",
110 | name: "speed",
111 | default: 0,
112 | },
113 | ],
114 | glsl: `_st.y += scrollY + time*speed; return _st;`,
115 | },
116 | {
117 | name: "modulateScrollY",
118 | type: "combineCoord",
119 | inputs: [
120 | {
121 | type: "float",
122 | name: "scrollY",
123 | default: 0.5,
124 | },
125 | {
126 | type: "float",
127 | name: "speed",
128 | default: 0,
129 | },
130 | ],
131 | glsl: ` _st.y += _c0.r*scrollY + time*speed; return _st;`,
132 | },
133 | ].forEach((x) => setFunction(x));
134 |
135 | console.log("hydra-nowrap is deprecated, I recomment using hydra-wrap and setting the wrapping to nowrap")
--------------------------------------------------------------------------------
/hydra-fractals.js:
--------------------------------------------------------------------------------
1 | {
2 | const getHydra = function () {
3 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
4 | ? "editor"
5 | : window.atom?.packages
6 | ? "atom"
7 | : "idk";
8 | if (whereami === "editor") {
9 | return window.hydraSynth;
10 | }
11 | if (whereami === "atom") {
12 | return global.atom.packages.loadedPackages["atom-hydra"]
13 | .mainModule.main.hydra;
14 | }
15 | let _h = [
16 | window.hydraSynth,
17 | window._hydra,
18 | window.hydra,
19 | window.h,
20 | window.H,
21 | window.hy
22 | ].find(h => h?.regl);
23 | return _h;
24 | };
25 | window._hydra = getHydra();
26 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
27 | }
28 |
29 | [
30 | {
31 | name: "mirrorX",
32 | type: "coord",
33 | inputs: [
34 | {
35 | type: "float",
36 | name: "pos",
37 | default: 0,
38 | },
39 | {
40 | type: "float",
41 | name: "coverage",
42 | default: 1,
43 | },
44 | ],
45 | glsl: `_st.x = (0.0-abs(fract(_st.x/coverage)-(1.0-0.5-pos))+0.5-pos)*coverage; return _st;`,
46 | },
47 | {
48 | name: "mirrorY",
49 | type: "coord",
50 | inputs: [
51 | {
52 | type: "float",
53 | name: "pos",
54 | default: 0,
55 | },
56 | {
57 | type: "float",
58 | name: "coverage",
59 | default: 1,
60 | },
61 | ],
62 | glsl: `_st.y = (0.0-abs(fract(_st.y/coverage)-(1.0-0.5-pos))+0.5-pos)*coverage; return _st;`,
63 | },
64 | {
65 | name: "mirrorX2",
66 | type: "coord",
67 | inputs: [
68 | {
69 | type: "float",
70 | name: "pos",
71 | default: 0,
72 | },
73 | {
74 | type: "float",
75 | name: "coverage",
76 | default: 1,
77 | },
78 | ],
79 | glsl: `_st.x = (abs(fract(_st.x/coverage)-(1.0-0.5-pos))+0.5-pos)*coverage; return _st;`,
80 | },
81 | {
82 | name: "mirrorY2",
83 | type: "coord",
84 | inputs: [
85 | {
86 | type: "float",
87 | name: "pos",
88 | default: 0,
89 | },
90 | {
91 | type: "float",
92 | name: "coverage",
93 | default: 1,
94 | },
95 | ],
96 | glsl: `_st.y = (0.0-abs(fract(_st.y/coverage)-(1.0-0.5-pos))+0.5-pos)*coverage; return _st;`,
97 | },
98 | {
99 | name: "mirrorWrap",
100 | type: "coord",
101 | inputs: [],
102 | glsl: `return -abs(fract(_st/2.0)*2.0-1.0)+1.0;`,
103 | },
104 | {
105 | name: "inversion",
106 | type: "coord",
107 | inputs: [],
108 | glsl: `_st /= dot(_st,_st); return _st;`,
109 | },
110 | ].forEach((x) => _hydra.synth.setFunction(x));
111 |
--------------------------------------------------------------------------------
/hydra-swizzle.js:
--------------------------------------------------------------------------------
1 | {
2 | const getHydra = function () {
3 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
4 | ? "editor"
5 | : window.atom?.packages
6 | ? "atom"
7 | : "idk";
8 | if (whereami === "editor") {
9 | return window.hydraSynth;
10 | }
11 | if (whereami === "atom") {
12 | return global.atom.packages.loadedPackages["atom-hydra"]
13 | .mainModule.main.hydra;
14 | }
15 | let _h = [
16 | window.hydraSynth,
17 | window._hydra,
18 | window.hydra,
19 | window.h,
20 | window.H,
21 | window.hy
22 | ].find(h => h?.regl);
23 | return _h;
24 | };
25 | window._hydra = getHydra();
26 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
27 | }
28 |
29 | {
30 | const gS = _hydraScope.osc().constructor.prototype;
31 | // https://stackoverflow.com/questions/34127294/
32 | function getSwizzles(coords) {
33 | function combinations(input, length, curstr) {
34 | if (curstr.length == length) return [curstr];
35 | var ret = [];
36 | for (var i = 0; i < input.length; i++) {
37 | ret.push.apply(
38 | ret,
39 | combinations(input, length, curstr + input[i])
40 | );
41 | }
42 | return ret;
43 | }
44 |
45 | let ret = combinations(coords, coords.length, "");
46 | ret.splice(ret.indexOf("input"), 1);
47 | return ret;
48 | }
49 | const threeComponents = [].concat(getSwizzles("rgb"), getSwizzles("xyz"));
50 |
51 | const fourComponents = [].concat(getSwizzles("rgba"), getSwizzles("xyzw"));
52 |
53 | function definePropertyFromMethod(method, newName = "") {
54 | newName = newName ? newName : method;
55 | Object.defineProperty(gS, newName, {
56 | configurable: true,
57 | get() {
58 | return this[method].bind(this)();
59 | },
60 | });
61 | }
62 |
63 | function returnSwizzleKeepingAlpha(swizzle){
64 | const containsAny = (str, chars) => [...chars].some(char => str.includes(char));
65 | const alpha = containsAny(swizzle, "rgb") ? "a" : "w";
66 | return `return _c0.${swizzle + alpha};`;
67 | }
68 |
69 | threeComponents.forEach((swizzle) => {
70 | const name = "_" + swizzle;
71 | _hydra.synth.setFunction({
72 | name,
73 | type: "color",
74 | inputs: [],
75 | glsl: returnSwizzleKeepingAlpha(swizzle),
76 | });
77 | definePropertyFromMethod(name, swizzle);
78 | });
79 | fourComponents.forEach((swizzle) => {
80 | const name = "_" + swizzle;
81 | _hydra.synth.setFunction({
82 | name,
83 | type: "color",
84 | inputs: [],
85 | glsl: `return _c0.${swizzle};`,
86 | });
87 | definePropertyFromMethod(name, swizzle);
88 | });
89 | Array.from("rgbaxyzw").forEach((elem) => {
90 | const name = "_swizzle_" + elem;
91 | _hydra.synth.setFunction({
92 | name,
93 | type: "color",
94 | inputs: [],
95 | glsl: returnSwizzleKeepingAlpha(elem.repeat(3)),
96 | });
97 | definePropertyFromMethod(name, elem);
98 | });
99 | }
100 |
--------------------------------------------------------------------------------
/doc/ES/hydra-glsl.md:
--------------------------------------------------------------------------------
1 | # hydra-glsl
2 |
3 | Este hack/extensión te permite codear GLSL casi que directamente adentro de Hydra. Añade 5 functiones, 1 por cada tipo de glsl-function que hay en Hydra
4 |
5 | ## Ejemplo:
6 | ```js
7 | glsl('vec4(sin(((_st.x*54.)+time*2.)*vec3(0.1,0.102,0.101)),1.0)')
8 | .diff(o0)
9 | .glslColor('vec4(c0.brg,1.)')
10 | .glslCoord('xy*=(1.0/vec2(i0, i0)); return xy',.25)
11 | .glslCombine('return c0-c1',o1)
12 | .glslCombineCoord('uv+(vec2(c0.r,c0.b)*0.1)',o1)
13 | .out()
14 | ```
15 | [Miralo en hydra!](https://hydra.ojack.xyz/?sketch_id=agiUw1vmrGmmf4Zy)
16 |
17 | ---
18 |
19 | ## Funciones:
20 |
21 | | función | argumentos dsps del código | tipo correspondiente | argumentos de glsl : aliases |
22 | |--------------------------|------------------|--------------------|-----------------------------------|
23 | | glsl() | ...args | 'src' | _st : st, uv, xy |
24 | | osc().glslColor() | ...args | 'color' | _c0 : c0, color |
25 | | osc().glslCoord() | ...args | 'coord' | _st : st, uv, xy |
26 | | osc().glslCombine() | texture, ...args | 'combine' | _c0 : c0, color0; _c1: c1, color1 |
27 | | osc().glslCombineCoord() | texture, ...args | 'combineCoord' | _st : st, uv, xy; _c0: c0, color |
28 |
29 | *Nótese que `osc()` es meramente un ejemplo*
30 |
31 | ### Extra functions
32 |
33 | | función | argumentos dsps del código | tipo correspondiente | descripción |
34 | |--------------------------|------------------|--------------------|-----------------------------------|
35 | | osc().glslHsv() | ...args | 'color' | Convierte los colores de c0 a HSV. Podés acceder y modificar estos valores desde un `vec3 hsv` |
36 |
37 | ---
38 |
39 | ## Argumentos
40 |
41 | Cada función trae con sigo 10 argumentos predeterminados con nombres `i0`,`i1`,`i2`...`i9`. Todos estos se inicializan con el valor por default de `1`. Podés usar estos 10 argumentos o definir los tuyos al mandar cada argumento en un array con un formate de `['nombre',valor]`.
42 |
43 | #### Importante:
44 | Todos los argumentos son del tipo `float`.
45 |
46 | ### Ejemplo:
47 |
48 | ```js
49 | glsl('vec4(sin(uv.x*i0+(time*i1*vec3(i2,i2*2.,i2*3.))),1.0)',16,2,.3)
50 | .glslColor('vec4(c0.brg-(sin(c0.b)*miVariable),1.)',['miVariable',0.2])
51 | .out()
52 | ```
53 |
54 | Hasta podés mandar funciones como variables como se suele hacer en Hydra:
55 |
56 | ```js
57 | glsl('vec4(sin(uv.x*i0+(time*i1*vec3(i2,i2*2.,i2*3.))),1.0)',16,2,.3)
58 | .glslColor('vec4(c0.brg-(sin(c0.b)*miVariable),1.)',['miVariable',()=>time%1])
59 | .out()
60 | ```
61 |
62 | ---
63 |
64 | ## Sobre el codigo (y el lazy code)
65 |
66 | * Podés usar de una cualquiera de los aliases descritos arriba.
67 | * Podés omitir el semicolón al final.
68 | * Podés omitir la palabra reservada "return".
69 | * Podes mandar código que ocupe múltiples líneas.
70 | * Solo podés omitir el semicolón en la ultima linea.
71 | * Podés aún así omitir la palabra return.
72 | * Podés escribir tus propias `c0`s, `st`s o cualquier otra variable llamada como alguna de los aliases de arriba. El script se fija que no hayas instanciado ninguna variable llamada así antes de definir los aliases.
73 | * No podes usar el mismo nombre de un alias como el nombre de un argumento
74 |
75 | ---
76 |
77 | ## Tip
78 |
79 | Tené la consola del browser abierta. Hydra no tira errores de frag a la consola integrada.
80 |
81 | ## Nota
82 |
83 | Este hack funciona llenando de nuevas funciones al contexto global (`window`) y/o al constructor de GlslSource. No te asustes si ves un montón de funciones llamdas `glsl_ext_NODE_`-algo.
84 |
--------------------------------------------------------------------------------
/doc/hydra-glsl.md:
--------------------------------------------------------------------------------
1 | # hydra-glsl
2 |
3 | This hack/extension allows you to use glsl code almost directly inside Hydra. It adds 5 functions, 1 according to each type of glsl-function in hydra.
4 |
5 | ## Example
6 |
7 | ```js
8 | glsl('vec4(sin(((_st.x*54.)+time*2.)*vec3(0.1,0.102,0.101)),1.0)')
9 | .diff(o0)
10 | .glslColor('vec4(c0.brg,1.)')
11 | .glslCoord('xy*=(1.0/vec2(i0, i0)); return xy',.25)
12 | .glslCombine('return c0-c1',o1)
13 | .glslCombineCoord('uv+(vec2(c0.r,c0.b)*0.1)',o1)
14 | .out()
15 | ```
16 |
17 | [Open in hydra!](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCdodHRwcyUzQSUyRiUyRmh5cGVyLWh5ZHJhLmdsaXRjaC5tZSUyRmh5ZHJhLWdsc2wuanMnKSUwQSUwQSUyRiUyRmh5ZHJhLWdsc2wlMEElMkYlMkZFeHRlbnNpb24lMjBmb3IlMjBjb2RpbmclMjBnbHNsJTIwb24lMjB0aGUlMjBmbHklMjBpbnNpZGUlMjBIeWRyYSUyMGNvZGUlMEElMkYlMkZieSUyMFJJVENIU0UlMEElMkYlMkZtb3JlJTIwaW5mbyUyMGFuZCUyMGRvY3MlM0ElMEElMkYlMkYlMDlodHRwcyUzQSUyRiUyRmdpdGh1Yi5jb20lMkZyaXRjaHNlJTJGaHlkcmEtZXh0ZW5zaW9ucyUyRmJsb2IlMkZtYWluJTJGZG9jJTJGaHlkcmEtZ2xzbC5tZCUwQSUwQWdsc2woJ3ZlYzQoc2luKCgoX3N0LngqNTQuKSUyQnRpbWUqMi4pKnZlYzMoMC4xJTJDMC4xMDIlMkMwLjEwMSkpJTJDMS4wKScpJTBBJTIwJTIwJTA5LmRpZmYobzApJTBBJTA5Lmdsc2xDb2xvcigndmVjNChjMC5icmclMkMxLiknKSUwQSUwOS5nbHNsQ29vcmQoJ3h5KiUzRCgxLjAlMkZ2ZWMyKGkwJTJDJTIwaTApKSUzQiUyMHJldHVybiUyMHh5JyUyQy4yNSklMEElMDkuZ2xzbENvbWJpbmUoJ3JldHVybiUyMGMwLWMxJyUyQ28xKSUwQSUwOS5nbHNsQ29tYmluZUNvb3JkKCd1diUyQih2ZWMyKGMwLnIlMkNjMC5iKSowLjEpJyUyQ28xKSUwQSUyMCUyMC5vdXQoKSUwQSUwQW5vaXNlKDMpJTBBJTA5Lm91dChvMSklMEE%3D)
18 |
19 | ---
20 |
21 | ## Functions
22 |
23 | | function | arguments after code | corresponding type | glsl arguments : aliases |
24 | |--------------------------|------------------|--------------------|-----------------------------------|
25 | | glsl() | ...args | 'src' | _st : st, uv, xy |
26 | | osc().glslColor() | ...args | 'color' | _c0 : c0, color |
27 | | osc().glslCoord() | ...args | 'coord' | _st : st, uv, xy |
28 | | osc().glslCombine() | texture, ...args | 'combine' | _c0 : c0, color0;_c1: c1, color1 |
29 | | osc().glslCombineCoord() | texture, ...args | 'combineCoord' | _st : st, uv, xy;_c0: c0, color |
30 |
31 | *Note that `osc()` is merely an example*
32 |
33 | ### Extra functions
34 |
35 | | function | arguments after code | corresponding type | description |
36 | |--------------------------|------------------|--------------------|-----------------------------------|
37 | | osc().glslHsv() | ...args | 'color' | Converts to and from HSV. With your code being placed in between. Pre-defines the HSV converted values as a `vec3 hsv`|
38 |
39 | ---
40 |
41 | ## Arguments
42 |
43 | Each function comes with 10 predefined inputs called `i0`,`i1`,`i2`...`i9`. All of which are defaulted to `1`. You can use either these 10 arguments or define your own by sending them as arrays in the form of `['name',value]`.
44 |
45 | #### Important
46 |
47 | All inputs are `float` as of now.
48 |
49 | ### Example
50 |
51 | ```js
52 | glsl('vec4(sin(uv.x*i0+(time*i1*vec3(i2,i2*2.,i2*3.))),1.0)',16,2,.3)
53 | .glslColor('vec4(c0.brg-(sin(c0.b)*myVariable),1.)',['myVariable',0.2])
54 | .out()
55 | ```
56 |
57 | You can even send arguments as functions in typical Hydra manner:
58 |
59 | ```js
60 | glsl('vec4(sin(uv.x*i0+(time*i1*vec3(i2,i2*2.,i2*3.))),1.0)',16,2,.3)
61 | .glslColor('vec4(c0.brg-(sin(c0.b)*myVariable),1.)',['myVariable',()=>time%1])
62 | .out()
63 | ```
64 |
65 | ---
66 |
67 | ## About the code (and lazy code)
68 |
69 | * You can straight up use any of the aliases mentioned above.
70 | * You can omit the semicolon at the end.
71 | * You can omit the return keyword.
72 | * You can use multiline code.
73 | * You can only omit the semicolon in the last line.
74 | * You can still omit the return keyword.
75 | * You can write your own `c0`s, `st`s or any other variables named like aliases mentioned above. The script checks if you defined any variables named like that before assigning the aliases.
76 | * You cannot use aliases as names of custom arguments
77 |
78 | ---
79 |
80 | ## Tip
81 |
82 | Have the browser's console open. Hydra doesn't show frag errors on the built-in console.
83 |
84 | ## Note
85 |
86 | This hack works by flooding either the global context (the `window`) or the GlslSource constructor with new Hydra functions. Don't be scared to find lots of functions called `glsl_ext_NODE_`-something.
87 |
--------------------------------------------------------------------------------
/doc/hydra-pixels.md:
--------------------------------------------------------------------------------
1 | # hydra-pixels
2 |
3 | ---
4 | This extension adds a functionality to each Hydra output that allows you to read the content of the pixels displayed.
5 |
6 | ## Example
7 |
8 | ```js
9 | osc(40,.09,1.5)
10 | .diff(osc(20).luma())
11 | .out()
12 |
13 | oct = ()=> shape(8,.3).diff(shape(8,.28)).luma()
14 | src(o0)
15 | .layer(
16 | oct()
17 | .color(1,0,0)
18 | .scale(()=>1+(pixel[0]/255))
19 | )
20 | .layer(
21 | oct()
22 | .color(0,0,1)
23 | .scale(()=>1+(pixel[2]/255))
24 | )
25 | .layer(src(o0).scale(128).mask(shape(4,.03,0)))
26 | .out(o1)
27 |
28 | render(o1)
29 |
30 | update = ()=> {
31 | pixel = o0.read(width/2,height/2) // center of the screen
32 | }
33 | ```
34 |
35 | [open in hydra](https://hydra.ojack.xyz/?code=JTJGJTJGJTIwbGljZW5zZWQlMjB3aXRoJTIwQ0MlMjBCWS1OQy1TQSUyMDQuMCUyMGh0dHBzJTNBJTJGJTJGY3JlYXRpdmVjb21tb25zLm9yZyUyRmxpY2Vuc2VzJTJGYnktbmMtc2ElMkY0LjAlMkYlMEElMkYlMkZoeWRyYS1waXhlbHMlMEElMkYlMkZyZWFkJTIwcGl4ZWxzJTIwZnJvbSUyMGVhY2glMjBoeWRyYSUyMG91dHB1dCUwQSUyRiUyRmJ5JTIwUklUQ0hTRSUwQSUwQWF3YWl0JTIwbG9hZFNjcmlwdCgnaHR0cHMlM0ElMkYlMkZoeXBlci1oeWRyYS5nbGl0Y2gubWUlMkZoeWRyYS1waXhlbHMuanMnKSUwQSUwQW9zYyg0MCUyQy4wOSUyQzEuNSklMEElMDkuZGlmZihvc2MoMjApLmx1bWEoKSklMEEub3V0KCklMEElMEFvY3QlMjAlM0QlMjAoKSUzRCUzRSUyMHNoYXBlKDglMkMuMykuZGlmZihzaGFwZSg4JTJDLjI4KSkubHVtYSgpJTBBc3JjKG8wKSUwQSUwOS5sYXllciglMEElMjAlMjAlMDklMDlvY3QoKSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUwOS5jb2xvcigxJTJDMCUyQzApJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTA5LnNjYWxlKCgpJTNEJTNFMSUyQihwaXhlbCU1QjAlNUQlMkYyNTUpKSUwQSUyMCUyMCUyMCUyMCklMEElMjAlMjAlMDkubGF5ZXIoJTBBJTIwJTIwJTA5JTA5b2N0KCklMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMDkuY29sb3IoMCUyQzAlMkMxKSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUwOS5zY2FsZSgoKSUzRCUzRTElMkIocGl4ZWwlNUIyJTVEJTJGMjU1KSklMEElMjAlMjAlMjAlMjApJTBBJTA5LmxheWVyKHNyYyhvMCkuc2NhbGUoMTI4KS5tYXNrKHNoYXBlKDQlMkMuMDMlMkMwKSkpJTBBJTA5Lm91dChvMSklMEElMEFyZW5kZXIobzEpJTBBJTBBdXBkYXRlJTIwJTNEJTIwKCklM0QlM0UlMjAlN0IlMEElMjAlMjBwaXhlbCUyMCUzRCUyMG8wLnJlYWQoaW5uZXJXaWR0aCUyRjIlMkNpbm5lckhlaWdodCUyRjIpJTBBJTdEJTBBJTJGJTJGJTIweW91JTIwSEFWRSUyMHRvJTIwdXNlJTIwdGhlJTIwdXBkYXRlJTIwZnVuY3Rpb24lMjAlMEElMkYlMkYlMjBhbmQlMjBhc3NpZ24lMjBwaXhlbHMlMjB0byUyMHZhcmlhYmxlcyUyMGJlZm9yZSUyMHVzaW5nJTIwdGhlbSUyMGFib3ZlJTBBJTJGJTJGJTIwaWYlMjB5b3UlMjBkb24ndCUyQyUyMGxldCdzJTIwc2F5JTIweW91JTIwdHJ5JTIwb3NjKCkucm90YXRlKCgpJTNEJTNFbzAucmVhZCgpJTVCMCU1RCklMkMlMEElMkYlMkYlMjB5b3UnbGwlMjBtYWtlJTIwYSUyMGZlZWRiYWNrJTIwbG9vcCUyMGJldHdlZW4lMjBmcmFtZWJ1ZmZlcnMlMjBuJTIwc3R1ZmYlMEElMEElMEElMEElMEE%3D)
36 |
37 | ---
38 |
39 | ## Functions
40 |
41 | `Output` refers to a hydra output such as `o0`, `o1`, etc.
42 |
43 | ### Output.read()
44 |
45 | `Output.read( x = 0, y = 0, w = 1, h = 1 )`
46 |
47 | * `x` :: x position from which to start reading
48 | * `y` :: y position from which to start reading
49 | * `w` :: width of the area to be read
50 | * `y` :: height of the area to be read
51 |
52 | By default this function returns only the pixel at the position specified by the two first arguments.
53 |
54 | ### Output.readAll()
55 |
56 | `Output.readAll()`
57 |
58 | Returns all pixels in the output.
59 |
60 | ## How to use them
61 |
62 | Any of the mentioned functions will return an array (actually, a Uint8Array) with all the pixels components in order. For example, retrieving one pixel with return something like `[255,0,20,240]`, each value corresponding to rgba accordingly. Retrieving two pixels will return something like `[255,0,20,240,250,0,10,240]`, with the rgba components of each pixel every 4 elements. Users of p5 will be familiar with this way of using arrays.
63 |
64 | ### Making Hydra react to pixels
65 |
66 | If you want Hydra to react to pixels you can't simply `osc().rotate(()=>o0.read()[0]).out()`, this will create a feedback between framebuffers or something like that (it throws an error and doesn't do what it's expected, that's the important bit innit?). In order to retrieve values every frame you have to first assign them to a variable in Hydra's `update` function. This is a function that runs every time a frame is processed, similar to p5's `draw`. The [example](#example) above shows this in action in the following bit:
67 |
68 | ```js
69 | update = ()=> {
70 | pixel = o0.read(innerWidth/2,innerHeight/2) // center of the screen
71 | }
72 | ```
73 |
74 | Now you can use `pixel` in your Hydra code.
75 |
76 | ### Warning
77 |
78 | Sending `read` values bigger than the width or height of the canvas as xy positions, or exceeding the canvas when sending values for the width and height of the area to read, can crash Hydra entirely.
79 |
--------------------------------------------------------------------------------
/hydra-gradientmap.js:
--------------------------------------------------------------------------------
1 | {
2 | const getHydra = function () {
3 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
4 | ? "editor"
5 | : window.atom?.packages
6 | ? "atom"
7 | : "idk";
8 | if (whereami === "editor") {
9 | return window.hydraSynth;
10 | }
11 | if (whereami === "atom") {
12 | return global.atom.packages.loadedPackages["atom-hydra"]
13 | .mainModule.main.hydra;
14 | }
15 | let _h = [
16 | window.hydraSynth,
17 | window._hydra,
18 | window.hydra,
19 | window.h,
20 | window.H,
21 | window.hy
22 | ].find(h => h?.regl);
23 | return _h;
24 | };
25 | window._hydra = getHydra();
26 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
27 | }
28 |
29 | _hydra.synth.setFunction({
30 | name: "lookupX",
31 | type: "color",
32 | inputs: [
33 | {
34 | name: "_tex",
35 | type: "sampler2D",
36 | default: o0,
37 | },
38 | {
39 | name: "yOffset",
40 | type: "float",
41 | default: 0,
42 | },
43 | {
44 | name: "blending",
45 | type: "float",
46 | default: 1,
47 | },
48 | ],
49 | glsl: `
50 | float lum = _luminance(_c0.rgb);
51 | vec2 pos = vec2(lum,yOffset);
52 | vec4 color = texture2D(_tex,pos);
53 | return mix(_c0,color,blending);
54 | `,
55 | });
56 |
57 | _hydra.synth.setFunction({
58 | name: "lookupY",
59 | type: "color",
60 | inputs: [
61 | {
62 | name: "_tex",
63 | type: "sampler2D",
64 | default: o0,
65 | },
66 | {
67 | name: "xOffset",
68 | type: "float",
69 | default: 0,
70 | },
71 | {
72 | name: "blending",
73 | type: "float",
74 | default: 1,
75 | },
76 | ],
77 | glsl: `
78 | float lum = _luminance(_c0.rgb);
79 | vec2 pos = vec2(xOffset,lum);
80 | vec4 color = texture2D(_tex,pos);
81 | return mix(_c0,color,blending);
82 | `,
83 | });
84 |
85 | {
86 | const hydraGradients = {};
87 | hydraGradients.resolution = 512;
88 |
89 | function createSource() {
90 | const { constructor: HydraSource, regl, pb, width, height } = _hydra.s[0];
91 | return new HydraSource({ regl, pb, width, height });
92 | }
93 |
94 | window.createLinearGradient = function(angle,...args) {
95 | const cssColorFrom = (color) => {
96 | const alpha = color.pop();
97 | const cssColor = `rgba(${color
98 | .map((cur) => Math.round(cur * 256))
99 | .join(" ")}/ ${alpha})`;
100 | return cssColor;
101 | };
102 |
103 | const normalizeArrayColor = (color) => {
104 | if (Array.isArray(color)) {
105 | return cssColorFrom(
106 | Array.from({ length: 4 }).map((_, i) => color[i] ?? Number(i === 3))
107 | );
108 | } else {
109 | return color;
110 | }
111 | };
112 |
113 | const generateSteps = (q) =>
114 | Array.from({ length: q }, (_, i) => i / (q - 1));
115 |
116 | const generateBounds = (angle) => {
117 | const radius = hydraGradients.resolution / 2;
118 | const [s, c] = [Math.sin(angle), Math.cos(angle)];
119 | const startX = radius - (c * radius);
120 | const startY = radius - (s * radius);
121 | const endX = radius + (c * radius);
122 | const endY = radius + (s * radius);
123 | return [startX, startY, endX, endY];
124 | }
125 | const bounds = generateBounds(angle);
126 | const canvas = document.createElement("canvas");
127 | canvas.width = hydraGradients.resolution;
128 | canvas.height = hydraGradients.resolution;
129 | const ctx = canvas.getContext("2d");
130 |
131 | const hasCustomSteps = Number.isFinite(args[1]);
132 | if (hasCustomSteps && args.length % 2 !== 0) args.push(1);
133 |
134 | const filterEvery = hasCustomSteps ? 2 : 1;
135 | let [colors, steps] = [
136 | args.filter((_, i) => i % filterEvery ^ 1).map(normalizeArrayColor),
137 | args.filter((_, i) => i % filterEvery),
138 | ];
139 | steps = steps.length ? steps : generateSteps(colors.length);
140 | const gradient = ctx.createLinearGradient(...bounds);
141 | colors.forEach((color, i) => gradient.addColorStop(steps[i], color));
142 |
143 | ctx.fillStyle = gradient;
144 | ctx.fillRect(0, 0, canvas.width, canvas.height);
145 |
146 | const source = createSource();
147 | source.init({ src: canvas }, { min: "linear", mag: "linear" });
148 |
149 | return source;
150 | }
151 |
152 | window.createGradient = (...args) => window.createLinearGradient(0,...args);
153 | }
154 |
--------------------------------------------------------------------------------
/hydra-tap.js:
--------------------------------------------------------------------------------
1 | // https://github.com/bahamas10/node-bpm/blob/master/bpm.js
2 | if (typeof exports !== 'undefined') {
3 | module.exports = BPM;
4 | module.exports.BPM = BPM;
5 | }
6 | function BPM() {
7 | this.count = 0;
8 | this.ts = 0;
9 | this.old_ts = 0;
10 | }
11 | BPM.prototype.tap = function () {
12 | this.ts = Date.now();
13 | if (!this.first_ts) this.first_ts = this.ts;
14 | var ret = {};
15 | // ignore the first tap
16 | if (this.old_ts) {
17 | var ms = this.ts - this.old_ts;
18 | var avg = 60000 * this.count / (this.ts - this.first_ts);
19 | ret.avg = avg;
20 | ret.ms = ms;
21 | }
22 | ret.count = ++this.count;
23 | // Store the old timestamp
24 | this.old_ts = this.ts;
25 | return ret;
26 | };
27 | BPM.prototype.reset = function () {
28 | this.count = 0;
29 | this.ts = 0;
30 | this.old_ts = 0;
31 | this.first_ts = 0;
32 | };
33 | window.BPM = BPM;
34 |
35 | {
36 | const getHydra = function () {
37 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
38 | ? "editor"
39 | : window.atom?.packages
40 | ? "atom"
41 | : "idk";
42 | if (whereami === "editor") {
43 | return window.hydraSynth;
44 | }
45 | if (whereami === "atom") {
46 | return global.atom.packages.loadedPackages["atom-hydra"]
47 | .mainModule.main.hydra;
48 | }
49 | let _h = [
50 | window.hydraSynth,
51 | window._hydra,
52 | window.hydra,
53 | window.h,
54 | window.H,
55 | window.hy
56 | ].find(h => h?.regl);
57 | return _h;
58 | };
59 | window._hydra = getHydra();
60 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
61 | }
62 |
63 | {
64 | const tapper = new BPM();
65 | window.hydraTap = {};
66 | hydraTap.resyncCall = () => 0;
67 | let resetInterval = 0;
68 |
69 | document.addEventListener('keydown', function (event) {
70 | if (event.ctrlKey && event.keyCode === 32 && !(event.shiftKey)) {
71 | clearInterval(resetInterval);
72 | const tap = tapper.tap();
73 | if (tap.count > 1) {
74 | _hydra.sandbox.set('bpm', Math.round(tap.avg));
75 | }
76 | resetInterval = setInterval(tapper.reset.bind(tapper), 1500);
77 | } else if (event.ctrlKey && event.key === ",") {
78 | _hydra.sandbox.set('time', hydraTap.resyncCall());
79 | }
80 | });
81 |
82 | function setRange(f) {
83 | f.range = (min = 0, max = 1) => () => f() * (max - min) + min;
84 | return f;
85 | }
86 | function setCurve(f) {
87 | f.curve = (q = 1) => {
88 | f2 = () => q > 0 ? Math.pow(f(), q) : (1 - Math.pow(1 - f(), -q));
89 | f2 = setRange(f2);
90 | return f2;
91 | };
92 | return f;
93 | }
94 | function rampToFunction(ramp) {
95 | ramp = setRange(ramp);
96 | ramp = setCurve(ramp);
97 | return ramp;
98 | }
99 |
100 | const rampUp = (x) => ((time * (1 / x)) % (60 / bpm)) / (60 / bpm);
101 | const rampDown = (x) => ((60 / bpm) - ((time * (1 / x)) % (60 / bpm))) / (60 / bpm);
102 | const rampTriUp = (x) => ((time * (1 / x)) % (60 * 2 / bpm)) >= (60 / bpm) ? rampUp(x) : rampDown(x);
103 | const rampTriDown = (x) => ((time * (1 / x)) % (60 * 2 / bpm)) >= (60 / bpm) ? rampDown(x) : rampUp(x);
104 |
105 | window.beats_ = (n = 1) => rampToFunction(() => rampUp(n))
106 | window.beats = (n = 1) => rampToFunction(() => rampDown(n))
107 | window.beatsTri_ = (n = 1) => rampToFunction(() => rampTriUp(n))
108 | window.beatsTri = (n = 1) => rampToFunction(() => rampTriDown(n))
109 |
110 | // speed controls
111 |
112 | document.addEventListener('keydown', function (event) {
113 | if (event.ctrlKey && event.shiftKey && event.altKey && event.code.startsWith('Digit')) {
114 | const number = parseInt(event.code.charAt(event.code.length - 1));
115 | const negativeSpeed = -number;
116 | _hydra.sandbox.set('speed', negativeSpeed);
117 | } else if (event.ctrlKey && event.shiftKey && event.code.startsWith('Digit')) {
118 | const number = parseInt(event.code.charAt(event.code.length - 1));
119 | _hydra.sandbox.set('speed', number);
120 | } else if (event.ctrlKey && event.altKey && event.code.startsWith('Digit')) {
121 | const number = parseInt(event.code.charAt(event.code.length - 1));
122 | const speed = 1 / number;
123 | _hydra.sandbox.set('speed', speed);
124 | }
125 | });
126 |
127 | let previousSpeed = _hydra.synth.speed;
128 | document.addEventListener('keydown', function (event) {
129 | if (event.ctrlKey && event.shiftKey && event.keyCode === 32) {
130 | if (_hydra.synth.speed !== 0) {
131 | previousSpeed = _hydra.synth.speed;
132 | _hydra.sandbox.set('speed', 0);
133 | } else {
134 | _hydra.sandbox.set('speed', previousSpeed);
135 | }
136 | }
137 | });
138 |
139 | }
140 |
--------------------------------------------------------------------------------
/hydra-blend.js:
--------------------------------------------------------------------------------
1 | {
2 | const getHydra = function () {
3 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
4 | ? "editor"
5 | : window.atom?.packages
6 | ? "atom"
7 | : "idk";
8 | if (whereami === "editor") {
9 | return window.hydraSynth;
10 | }
11 | if (whereami === "atom") {
12 | return global.atom.packages.loadedPackages["atom-hydra"]
13 | .mainModule.main.hydra;
14 | }
15 | let _h = [
16 | window.hydraSynth,
17 | window._hydra,
18 | window.hydra,
19 | window.h,
20 | window.H,
21 | window.hy
22 | ].find(h => h?.regl);
23 | return _h;
24 | };
25 | window._hydra = getHydra();
26 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
27 | }
28 |
29 | {
30 | const blendingFuncs = {
31 | add2: "min(base+blend,1.0)",
32 | average: "(base+blend)/2.0",
33 | colorBurn: "(blend==0.0)?blend:max((1.0-((1.0-base)/blend)),0.0)",
34 | colorDodge: "(blend==1.0)?blend:min(base/(1.0-blend),1.0)",
35 | darken: "min(blend,base)",
36 | difference: "abs(base-blend)",
37 | divide: "min(base/(blend+0.00000001),1.0)",
38 | exclusion: "base+blend-2.0*base*blend",
39 | glow: "(base==1.0)?base:min(blend*blend/(1.0-base),1.0)",
40 | hardLight:
41 | "blend<0.5?(2.0*blend*base):(1.0-2.0*(1.0-blend)*(1.0-base))",
42 | hardMix:
43 | "(((blend<0.5)?((blend==0.0)?(blend):max((1.0-((1.0-base)/(2.0*blend))),0.0)):(((2.0*(blend-0.5))==1.0)?(2.0*(blend-0.5)):min(base/(1.0-(2.0*(blend-0.5))),1.0)))<0.5)?0.0:1.0",
44 | lighten: "max(blend,base)",
45 | linearBurn: "max(base+blend-1.0,0.0)",
46 | linearDodge: "min(base+blend,1.0)",
47 | linearLight:
48 | "blend<0.5?(max(base+(2.0*blend)-1.0,0.0)):min(base+(2.0*(blend-0.5)),1.0)",
49 | multiply: "base*blend",
50 | negation: "1.0-abs(1.0-base-blend)",
51 | overlay: "base<0.5?(2.0*base*blend):(1.0-2.0*(1.0-base)*(1.0-blend))",
52 | phoenix: "min(base,blend)-max(base,blend)+vec3(1.0)",
53 | pinLight: "(blend<0.5)?min(base,2.0*blend):max(base,2.0*(blend-0.5))",
54 | reflect: "(blend==1.0)?blend:min(base*base/(1.0-blend),1.0)",
55 | screen: "1.0-((1.0-base)*(1.0-blend))",
56 | softLight:
57 | "(blend<0.5)?(2.0*base*blend+base*base*(1.0-2.0*blend)):(sqrt(base)*(2.0*blend-1.0)+2.0*base*(1.0-blend))",
58 | subtract: "max(base+blend-1.0,0.0)",
59 | vividLight:
60 | "(blend<0.5)?((blend==0.0)?(blend):max((1.0-((1.0-base)/(2.0*blend))),0.0)):(((2.0*(blend-0.5))==1.0)?(2.0*(blend-0.5)):min(base/(1.0-(2.0*(blend-0.5))),1.0))",
61 | };
62 |
63 | Object.entries(blendingFuncs).forEach(([mode, def]) => {
64 | let glsl =
65 | "vec3 rgb;\n\n" +
66 | //"_c0 = clamp(_c0, 0.0, 1.0);" +
67 | //"_c1 = clamp(_c1, 0.0, 1.0);" +
68 | ["r", "g", "b"].reduce((acc, elem) => {
69 | return (
70 | acc +
71 | (`rgb.${elem} = ` +
72 | def
73 | .replaceAll("base", "_c0." + elem)
74 | .replaceAll("blend", "_c1." + elem) +
75 | ";\n\n")
76 | );
77 | }, "") +
78 | "_c1.a *= amount;" +
79 | "vec4 blended = vec4(mix(_c0.rgb, rgb, _c1.a), 1.0);" +
80 | "vec4 over = _c1+(_c0*(1.0-_c1.a));" +
81 | "return mix(blended, over, 1.0-_c0.a);";
82 | _hydra.synth.setFunction({
83 | name: mode,
84 | type: "combine",
85 | inputs: [{ name: "amount", type: "float", default: 1 }],
86 | glsl,
87 | });
88 | });
89 | }
90 |
91 | _hydra.synth.setFunction({
92 | name: "layer",
93 | type: "combine",
94 | inputs: [
95 | {
96 | type: "float",
97 | name: "amount",
98 | default: 1,
99 | },
100 | ],
101 | glsl: `
102 | _c0.a = clamp(_c0.a, 0.0, 1.0);
103 | _c1.a = clamp(_c1.a, 0.0, 1.0);
104 | return _c1+(_c0*(1.0-_c1.a));
105 | `,
106 | });
107 | _hydra.synth.setFunction({
108 | name: "mask",
109 | type: "combine",
110 | inputs: [],
111 | glsl: `
112 | float a = _luminance(_c1.rgb);
113 | return vec4(_c0.rgb*a, _c0.a*a);
114 | `,
115 | });
116 | _hydra.synth.setFunction({
117 | name: "luma",
118 | type: "color",
119 | inputs: [
120 | {
121 | type: "float",
122 | name: "threshold",
123 | default: 0.5,
124 | },
125 | {
126 | type: "float",
127 | name: "tolerance",
128 | default: 0.1,
129 | },
130 | ],
131 | glsl: `
132 | float a = smoothstep(threshold-(tolerance+0.0000001), threshold+(tolerance+0.0000001), _luminance(_c0.rgb*_c0.a));
133 | return vec4(_c0.rgb*a, a);
134 | `,
135 | });
136 | _hydra.synth.setFunction({
137 | name: "clamp",
138 | type: "color",
139 | inputs: [],
140 | glsl: `
141 | return clamp(_c0,0.0,1.0);
142 | `,
143 | });
144 | _hydra.synth.setFunction({
145 | name: "premultiply",
146 | type: "color",
147 | inputs: [],
148 | glsl: `
149 | _c0 = clamp(_c0,0.0,1.0);
150 | return vec4(_c0.rgb*_c0.a,_c0.a);
151 | `,
152 | });
153 |
154 | {
155 | const gS = _hydraScope.osc().constructor.prototype;
156 |
157 | gS.pm = gS.premultiply;
158 |
159 | gS.negate = gS.negation;
160 | }
161 |
--------------------------------------------------------------------------------
/hydra-src.js:
--------------------------------------------------------------------------------
1 | {
2 | const getHydra = function () {
3 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
4 | ? "editor"
5 | : window.atom?.packages
6 | ? "atom"
7 | : "idk";
8 | if (whereami === "editor") {
9 | return window.hydraSynth;
10 | }
11 | if (whereami === "atom") {
12 | return global.atom.packages.loadedPackages["atom-hydra"]
13 | .mainModule.main.hydra;
14 | }
15 | let _h = [
16 | window.hydraSynth,
17 | window._hydra,
18 | window.hydra,
19 | window.h,
20 | window.H,
21 | window.hy
22 | ].find(h => h?.regl);
23 | return _h;
24 | };
25 | window._hydra = getHydra();
26 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
27 | }
28 |
29 | {
30 | const canvas = _hydra.canvas;
31 | const scope = (_hydraScope.srcMask = function (tex) {
32 | return _hydraScope.src(tex).mask(shape(4, 1, 0));
33 | });
34 | _hydraScope.srcAbs = function (tex) {
35 | if (!tex.hasOwnProperty("src")) return src(tex);
36 | const w = () => tex.src?.width || tex.src?.videoWidth || 0;
37 | const h = () => tex.src?.height || tex.src?.videoHeight || 0;
38 | return _hydraScope.src(tex).scale(
39 | 1,
40 | () => w() / canvas.clientWidth,
41 | () => h() / canvas.clientHeight
42 | );
43 | };
44 | _hydraScope.srcAbsMask = function (tex) {
45 | if (!tex.hasOwnProperty("src")) return src(tex);
46 | const w = () => tex.src?.width || tex.src?.videoWidth || 0;
47 | const h = () => tex.src?.height || tex.src?.videoHeight || 0;
48 | return _hydraScope.srcMask(tex).scale(
49 | 1,
50 | () => w() / canvas.clientWidth,
51 | () => h() / canvas.clientHeight
52 | );
53 | };
54 | _hydraScope.srcRel = function (tex) {
55 | if (!tex.hasOwnProperty("src")) return src(tex);
56 | const w = () =>
57 | tex.src?.width
58 | ? tex.src?.width / tex.src?.height
59 | : tex.src?.videoWidth
60 | ? tex.src?.videoWidth / tex.src?.videoHeight
61 | : 0;
62 | const h = () =>
63 | tex.src?.height
64 | ? tex.src?.height / tex.src?.width
65 | : tex.src?.videoHeight
66 | ? tex.src?.videoHeight / tex.src?.videoWidth
67 | : 0;
68 | const cw = () => canvas.clientWidth / canvas.clientHeight;
69 | const ch = () => canvas.clientHeight / canvas.clientWidth;
70 | return _hydraScope.src(tex).scale(
71 | 1,
72 | () => {
73 | const _cw = cw();
74 | const _w = w();
75 | return _cw > _w ? _w / _cw : 1;
76 | },
77 | () => {
78 | const _ch = ch();
79 | const _h = h();
80 | return _ch > _h ? _h / _ch : 1;
81 | }
82 | );
83 | };
84 | _hydraScope.srcRelMask = function (tex) {
85 | if (!tex.hasOwnProperty("src")) return src(tex);
86 | const w = () =>
87 | tex.src?.width
88 | ? tex.src?.width / tex.src?.height
89 | : tex.src?.videoWidth
90 | ? tex.src?.videoWidth / tex.src?.videoHeight
91 | : 0;
92 | const h = () =>
93 | tex.src?.height
94 | ? tex.src?.height / tex.src?.width
95 | : tex.src?.videoHeight
96 | ? tex.src?.videoHeight / tex.src?.videoWidth
97 | : 0;
98 | const cw = () => canvas.clientWidth / canvas.clientHeight;
99 | const ch = () => canvas.clientHeight / canvas.clientWidth;
100 | return _hydraScope.srcMask(tex).scale(
101 | 1,
102 | () => {
103 | const _cw = cw();
104 | const _w = w();
105 | return _cw > _w ? _w / _cw : 1;
106 | },
107 | () => {
108 | const _ch = ch();
109 | const _h = h();
110 | return _ch > _h ? _h / _ch : 1;
111 | }
112 | );
113 | };
114 |
115 | const gS = _hydraScope.osc().constructor.prototype;
116 | gS.rotateRel = function(...args){
117 | return this .scale(1,canvas.clientWidth/canvas.clientHeight)
118 | .rotate(...args)
119 | .scale(1,canvas.clientHeight/canvas.clientWidth)
120 | }
121 | gS.correctScaleRel = function(source){
122 | const tex = source;
123 | if (!tex.hasOwnProperty("src")) return src(tex);
124 | const w = () =>
125 | tex.src?.width
126 | ? tex.src?.width / tex.src?.height
127 | : tex.src?.videoWidth
128 | ? tex.src?.videoWidth / tex.src?.videoHeight
129 | : 0;
130 | const h = () =>
131 | tex.src?.height
132 | ? tex.src?.height / tex.src?.width
133 | : tex.src?.videoHeight
134 | ? tex.src?.videoHeight / tex.src?.videoWidth
135 | : 0;
136 | const cw = () => canvas.clientWidth / canvas.clientHeight;
137 | const ch = () => canvas.clientHeight / canvas.clientWidth;
138 | return this.scale(
139 | 1,
140 | () => {
141 | const _cw = cw();
142 | const _w = w();
143 | return _cw > _w ? _w / _cw : 1;
144 | },
145 | () => {
146 | const _ch = ch();
147 | const _h = h();
148 | return _ch > _h ? _h / _ch : 1;
149 | }
150 | );
151 | }
152 | gS.noWrap = function(sm=0){
153 | return this.mask(shape(4, 1, sm));
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/hydra-text.js:
--------------------------------------------------------------------------------
1 | {
2 | const getHydra = function () {
3 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
4 | ? "editor"
5 | : window.atom?.packages
6 | ? "atom"
7 | : "idk";
8 | if (whereami === "editor") {
9 | return window.hydraSynth;
10 | }
11 | if (whereami === "atom") {
12 | return global.atom.packages.loadedPackages["atom-hydra"]
13 | .mainModule.main.hydra;
14 | }
15 | let _h = [
16 | window.hydraSynth,
17 | window._hydra,
18 | window.hydra,
19 | window.h,
20 | window.H,
21 | window.hy
22 | ].find(h => h?.regl);
23 | return _h;
24 | };
25 | window._hydra = getHydra();
26 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
27 | }
28 |
29 | _hydraScope.srcRelMask = function (tex) {
30 | if (!tex.hasOwnProperty("src")) return src(tex);
31 | const w = () =>
32 | tex.src?.width
33 | ? tex.src?.width / tex.src?.height
34 | : tex.src?.videoWidth
35 | ? tex.src?.videoWidth / tex.src?.videoHeight
36 | : 0;
37 | const h = () =>
38 | tex.src?.height
39 | ? tex.src?.height / tex.src?.width
40 | : tex.src?.videoHeight
41 | ? tex.src?.videoHeight / tex.src?.videoWidth
42 | : 0;
43 | const cw = () => _hydra.canvas.clientWidth / _hydra.canvas.clientHeight;
44 | const ch = () => _hydra.canvas.clientHeight / _hydra.canvas.clientWidth;
45 | return _hydraScope
46 | .src(tex)
47 | .mask(shape(4, 1, 0))
48 | .scale(
49 | 1,
50 | () => {
51 | const _cw = cw();
52 | const _w = w();
53 | return _cw > _w ? _w / _cw : 1;
54 | },
55 | () => {
56 | const _ch = ch();
57 | const _h = h();
58 | return _ch > _h ? _h / _ch : 1;
59 | }
60 | );
61 | };
62 |
63 | {
64 | const Source = _hydra.s[0].constructor;
65 | window.hydraText = {
66 | font: "sans-serif",
67 | fontStyle: "normal",
68 | fontSize: "auto",
69 | textAlign: "center",
70 | fillStyle: "white",
71 | strokeStyle: "white",
72 | lineWidth: "2%",
73 | lineJoin: "miter",
74 | canvasResize: 2,
75 | interpolation: "linear"
76 | };
77 |
78 | function createSource() {
79 | const s = new Source({
80 | regl: _hydra.regl,
81 | pb: _hydra.pb,
82 | width: _hydra.width,
83 | height: _hydra.height,
84 | });
85 | return s;
86 | }
87 | function isPercentage(property){
88 | return String(property).endsWith("%");
89 | }
90 | function getPercentage(property){
91 | return Number(property.substring(0,property.length-1)) / 100;
92 | }
93 | const _text = function (str, _config, fill = true, stroke = false, fillAfter = false) {
94 | const s = createSource();
95 | const canvas = document.createElement("canvas");
96 | const ctx = canvas.getContext("2d");
97 | const lines = str.split("\n");
98 | const longestLine = lines.reduce((a,b) => a.length > b.length ? a : b );
99 |
100 | if (typeof _config == "string") _config = { font: _config };
101 |
102 | const config = Object.assign({}, hydraText);
103 | Object.assign(config, _config);
104 | const font = config.font;
105 | config.font = undefined;
106 | const fontStyle = config.fontStyle;
107 | config.fontStyle = undefined;
108 | config.textBaseline = "middle";
109 |
110 | const fontWithSize = (size) => `${fontStyle} ${size} ${font}`;
111 |
112 | Object.assign(ctx, config);
113 |
114 | canvas.width = _hydra.width;
115 | ctx.font = fontWithSize("1px");
116 | let padding = _hydra.width / 20;
117 | let textWidth = _hydra.width - padding;
118 | let fontSize = textWidth / ctx.measureText(longestLine).width;
119 | canvas.height = fontSize * 1.4 * lines.length;
120 |
121 | if(isPercentage(config.fontSize)) fontSize *= getPercentage(config.fontSize);
122 | else if (config.fontSize != "auto") fontSize = Number(config.fontSize.replace(/[^0-9.,]+/, ''));
123 | if(isPercentage(config.lineWidth)) config.lineWidth = fontSize * getPercentage(config.lineWidth);
124 | config.fontSize = undefined;
125 |
126 | fontSize *= config.canvasResize;
127 | canvas.width *= config.canvasResize;
128 | canvas.height *= config.canvasResize;
129 | textWidth *= config.canvasResize;
130 | padding *= config.canvasResize;
131 | config.lineWidth *= config.canvasResize;
132 |
133 | config.font = fontWithSize(String(fontSize) + "px");
134 | Object.assign(ctx, config);
135 |
136 | let x = 0;
137 | if (ctx.textAlign == "center") x = canvas.width / 2;
138 | else if (ctx.textAlign == "left") x = padding / 2;
139 | else if (ctx.textAlign == "right") x = canvas.width - padding / 2;
140 |
141 | lines.forEach((line, i) => {
142 | const y = (canvas.height / (lines.length + 1)) * (i + 1);
143 | if (fill) ctx.fillText(line, x, y, textWidth);
144 | if (stroke) ctx.strokeText(line, x, y, textWidth);
145 | if (fillAfter) ctx.fillText(line, x, y, textWidth);
146 | });
147 |
148 | s.init({ src: canvas }, { min: config.interpolation, mag: config.interpolation });
149 |
150 | return _hydraScope.srcRelMask(s);
151 | };
152 | _hydraScope.text = function (str, config) {
153 | return _text(str, config);
154 | };
155 | _hydraScope.strokeText = function (str, config) {
156 | return _text(str, config, false, true);
157 | };
158 | _hydraScope.fillStrokeText = function (str, config) {
159 | return _text(str, config, true, true, false);
160 | };
161 | _hydraScope.strokeFillText = function (str, config) {
162 | return _text(str, config, false, true, true);
163 | };
164 | }
165 |
--------------------------------------------------------------------------------
/hydra-debug.js:
--------------------------------------------------------------------------------
1 | {
2 | const getHydra = function () {
3 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
4 | ? "editor"
5 | : window.atom?.packages
6 | ? "atom"
7 | : "idk";
8 | if (whereami === "editor") {
9 | return window.hydraSynth;
10 | }
11 | if (whereami === "atom") {
12 | return global.atom.packages.loadedPackages["atom-hydra"]
13 | .mainModule.main.hydra;
14 | }
15 | let _h = [
16 | window.hydraSynth,
17 | window._hydra,
18 | window.hydra,
19 | window.h,
20 | window.H,
21 | window.hy
22 | ].find(h => h?.regl);
23 | return _h;
24 | };
25 | window._hydra = getHydra();
26 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
27 | }
28 |
29 | {
30 | async function main() {
31 | await _hydraScope.loadScript(
32 | "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"
33 | );
34 | await _hydraScope.loadScript(
35 | "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/glsl.min.js"
36 | );
37 | await _hydraScope.loadScript(
38 | "https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.7/beautify.js"
39 | );
40 |
41 | hljs.configure({ ignoreUnescapedHTML: true });
42 | const brPlugin = {
43 | "before:highlightBlock": ({ block }) => {
44 | block.innerHTML = block.innerHTML
45 | .replace(/\n/g, "")
46 | .replace(/
/g, "\n");
47 | },
48 | "after:highlightBlock": ({ result }) => {
49 | result.value = result.value.replace(/\n/g, "
");
50 | },
51 | };
52 | hljs.addPlugin(brPlugin);
53 |
54 | const link = document.createElement("link");
55 | link.href =
56 | "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/base16/tomorrow-night.min.css";
57 | link.type = "text/css";
58 | link.rel = "stylesheet";
59 | document.getElementsByTagName("head")[0].appendChild(link);
60 |
61 | {
62 | function cleanCode(code) {
63 | return js_beautify(code).replace(/\n{2,}/gm, "\n\n") + "\n\n";
64 | }
65 | function logHighlightedCode(glslSource, output) {
66 | let passes = glslSource.glsl();
67 | let code = passes[0].frag;
68 |
69 | document.getElementById("hydra-debug")?.remove();
70 |
71 | const pre = document.createElement("pre");
72 | pre.className = "hljs";
73 | pre.style.position = "sticky";
74 | pre.style.height = "96%";
75 | pre.style.padding = "4%";
76 | pre.style.overflow = "scroll";
77 | const codeElement = document.createElement("code");
78 | codeElement.className = "language-glsl";
79 | pre.appendChild(codeElement);
80 | codeElement.innerText = cleanCode(code)
81 | .replace(/&/g, "&")
82 | .replace(//g, ">")
84 | .replace(/"/g, """)
85 | .replace(/'/g, "'");
86 | hljs.highlightElement(pre, {
87 | language: "glsl",
88 | ignoreIllegals: true,
89 | });
90 |
91 | const wrapper = document.createElement("div");
92 | wrapper.id = "hydra-debug";
93 | wrapper.style.zIndex = 999;
94 | wrapper.style.overflow = "hidden";
95 | wrapper.style.position = "fixed";
96 | wrapper.style.width = "40%";
97 | wrapper.style.height = "90%";
98 | wrapper.style.left = "58%";
99 | wrapper.style.top = "5%";
100 | wrapper.style.fontSize = "14px";
101 |
102 | const close = document.createElement("button");
103 | close.innerText = "x";
104 | close.style.position = "absolute";
105 | close.style.right = "0px";
106 | close.style.top = "2%";
107 | close.style.fontSize = "20px";
108 | close.style.backgroundColor = "white";
109 | close.style.color = "black";
110 | close.style.border = "none";
111 | close.onclick = () => {
112 | document.getElementById("hydra-debug")?.remove();
113 | };
114 |
115 | wrapper.appendChild(pre);
116 | wrapper.appendChild(close);
117 |
118 | if (output) {
119 | pre.contentEditable = "true";
120 | const run = document.createElement("button");
121 | run.innerText = ">";
122 | run.style.position = "absolute";
123 | run.style.right = "30px";
124 | run.style.top = "2%";
125 | run.style.fontSize = "20px";
126 | run.style.backgroundColor = "white";
127 | run.style.color = "black";
128 | run.style.border = "none";
129 | run.onclick = () => {
130 | codeElement.innerText = cleanCode(pre.innerText)
131 | pre.innerHTML = "";
132 | pre.appendChild(codeElement);
133 | hljs.highlightElement(pre, {
134 | language: "glsl",
135 | ignoreIllegals: true,
136 | });
137 | passes[0].frag = pre.innerText
138 | .replace("&", "&")
139 | .replace("<", "<")
140 | .replace(">", ">")
141 | .replace(""", '"')
142 | .replace("'", "'");
143 | output.render(passes);
144 | };
145 | wrapper.appendChild(run);
146 | }
147 |
148 | document.body.append(wrapper);
149 | }
150 |
151 | const gS = _hydraScope.osc().constructor.prototype;
152 | gS.debug = function (output) {
153 | logHighlightedCode(this, output);
154 | return output ? this.out(output) : this;
155 | };
156 | }
157 | }
158 |
159 | main();
160 | }
161 |
--------------------------------------------------------------------------------
/hydra-glsl.js:
--------------------------------------------------------------------------------
1 | //hydra-gsls
2 | //code glsl on the fly inside Hydra code
3 |
4 | {
5 | const getHydra = function () {
6 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
7 | ? "editor"
8 | : window.atom?.packages
9 | ? "atom"
10 | : "idk";
11 | if (whereami === "editor") {
12 | return window.hydraSynth;
13 | }
14 | if (whereami === "atom") {
15 | return global.atom.packages.loadedPackages["atom-hydra"]
16 | .mainModule.main.hydra;
17 | }
18 | let _h = [
19 | window.hydraSynth,
20 | window._hydra,
21 | window.hydra,
22 | window.h,
23 | window.H,
24 | window.hy
25 | ].find(h => h?.regl);
26 | return _h;
27 | };
28 | window._hydra = getHydra();
29 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
30 | }
31 |
32 | {
33 | const gS = _hydraScope.osc().constructor.prototype;
34 | const _glslExtension = {
35 | inputArray: () =>
36 | new Array(10)
37 | .fill("i")
38 | .map((x, i) => ({ name: x + i, type: "float", default: 1 })),
39 | nodeCount: 0,
40 | checkCode: function (code) {
41 | code = code.trim();
42 | let lines = code.split(";");
43 | let ll = lines.length - 1;
44 | if (!lines[ll]) {
45 | lines.pop();
46 | ll--;
47 | }
48 | lines[ll] = lines[ll].trim();
49 | lines[ll] =
50 | "\n" +
51 | (lines[ll].substring(0, 6) != "return"
52 | ? "return " + lines[ll]
53 | : lines[ll]) +
54 | ";";
55 | code = lines.join(";");
56 | return code;
57 | },
58 | getObjAndArgs: function (type, args) {
59 | let inputArray = false;
60 | if (args[0] instanceof Array && args[0][0].constructor === String) {
61 | inputArray = this.inputArray().map((x, i) => {
62 | x.name = args[i] ? args[i][0] : x.name;
63 | return x;
64 | });
65 | inputArray = inputArray.slice(0, args.length);
66 | args = args.map((x) => x[1]);
67 | }
68 | let obj = {
69 | name: "_glsl_ext_NODE_" + this.nodeCount,
70 | type: type,
71 | inputs: inputArray || this.inputArray(),
72 | };
73 | this.nodeCount++;
74 | return [obj, args];
75 | },
76 | glslSource: function (code, ...args) {
77 | let prefix = [
78 | !code.includes("vec2 uv") ? "vec2 uv = _st;\n" : "",
79 | !code.includes("vec2 st") ? "vec2 st = _st;\n" : "",
80 | !code.includes("vec2 xy") ? "vec2 xy = _st;\n" : "",
81 | ].join("");
82 | let data = this.getObjAndArgs("src", args);
83 | let obj = data[0];
84 | args = data[1];
85 | obj.glsl = prefix + this.checkCode(code);
86 | _hydra.synth.setFunction(obj);
87 | return globalThis[obj.name](...args);
88 | },
89 | glslColor: function (self, code, ...args) {
90 | let prefix = [
91 | !code.includes("vec4 c0") ? "vec4 c0 = _c0;\n" : "",
92 | !code.includes("vec4 color") ? "vec4 color = _c0;\n" : "",
93 | ].join("");
94 | let data = this.getObjAndArgs("color", args);
95 | let obj = data[0];
96 | args = data[1];
97 | obj.glsl = prefix + this.checkCode(code);
98 | _hydra.synth.setFunction(obj);
99 | return gS[obj.name].bind(self)(...args);
100 | },
101 | glslHsv: function (self, code, ...args) {
102 | code = "vec3 hsv = _rgbToHsv(c0.rgb);\n" + code;
103 | code = code + "\nreturn vec4(_hsvToRgb(hsv),c0.a);";
104 | return this.glslColor(self, code, ...args);
105 | },
106 | glslCoord: function (self, code, ...args) {
107 | let prefix = [
108 | !code.includes("vec2 uv") ? "vec2 uv = _st;\n" : "",
109 | !code.includes("vec2 st") ? "vec2 st = _st;\n" : "",
110 | !code.includes("vec2 xy") ? "vec2 xy = _st;\n" : "",
111 | ].join("");
112 | let data = this.getObjAndArgs("coord", args);
113 | let obj = data[0];
114 | args = data[1];
115 | obj.glsl = prefix + this.checkCode(code);
116 | _hydra.synth.setFunction(obj);
117 | return gS[obj.name].bind(self)(...args);
118 | },
119 | glslCombine: function (self, code, texture, ...args) {
120 | let prefix = [
121 | !code.includes("vec4 c0") ? "vec4 c0 = _c0;\n" : "",
122 | !code.includes("vec4 color0") ? "vec4 color0 = _c0;\n" : "",
123 | !code.includes("vec4 c1") ? "vec4 c1 = _c1;\n" : "",
124 | !code.includes("vec4 color1") ? "vec4 color1 = _c1;\n" : "",
125 | ].join("");
126 | let data = this.getObjAndArgs("combine", args);
127 | let obj = data[0];
128 | args = data[1];
129 | args.unshift(texture);
130 | obj.glsl = prefix + this.checkCode(code);
131 | _hydra.synth.setFunction(obj);
132 | return gS[obj.name].bind(self)(...args);
133 | },
134 | glslCombineCoord: function (self, code, texture, ...args) {
135 | let prefix = [
136 | !code.includes("vec4 c0") ? "vec4 c0 = _c0;\n" : "",
137 | !code.includes("vec4 color") ? "vec4 color = _c0;\n" : "",
138 | !code.includes("vec2 uv") ? "vec2 uv = _st;\n" : "",
139 | !code.includes("vec2 st") ? "vec2 st = _st;\n" : "",
140 | !code.includes("vec2 xy") ? "vec2 xy = _st;\n" : "",
141 | ].join("");
142 | let data = this.getObjAndArgs("combineCoord", args);
143 | let obj = data[0];
144 | args = data[1];
145 | args.unshift(texture);
146 | obj.glsl = prefix + this.checkCode(code);
147 | _hydra.synth.setFunction(obj);
148 | return gS[obj.name].bind(self)(...args);
149 | },
150 | };
151 |
152 | _hydraScope.glsl = _glslExtension.glslSource.bind(_glslExtension);
153 | gS.glslColor = function (code, ...args) {
154 | return _glslExtension.glslColor(this, code, ...args);
155 | };
156 | gS.glslHsv = function (code, ...args) {
157 | return _glslExtension.glslHsv(this, code, ...args);
158 | };
159 | gS.glslCoord = function (code, ...args) {
160 | return _glslExtension.glslCoord(this, code, ...args);
161 | };
162 | gS.glslCombine = function (code, texture, ...args) {
163 | return _glslExtension.glslCombine(this, code, texture, ...args);
164 | };
165 | gS.glslBlend = gS.glslCombine;
166 | gS.glslCombineCoord = function (code, texture, ...args) {
167 | return _glslExtension.glslCombineCoord(this, code, texture, ...args);
168 | };
169 | gS.glslModulate = gS.glslCombineCoord;
170 | }
171 |
--------------------------------------------------------------------------------
/hydra-wrap.js:
--------------------------------------------------------------------------------
1 | // prereq
2 |
3 | //reset fbos. make sure they use clamp
4 | //code taken from hydra-outputs.js
5 |
6 | {
7 | const getHydra = function () {
8 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
9 | ? "editor"
10 | : window.atom?.packages
11 | ? "atom"
12 | : "idk";
13 | if (whereami === "editor") {
14 | return window.hydraSynth;
15 | }
16 | if (whereami === "atom") {
17 | return global.atom.packages.loadedPackages["atom-hydra"]
18 | .mainModule.main.hydra;
19 | }
20 | let _h = [
21 | window.hydraSynth,
22 | window._hydra,
23 | window.hydra,
24 | window.h,
25 | window.H,
26 | window.hy
27 | ].find(h => h?.regl);
28 | return _h;
29 | };
30 | window._hydra = getHydra();
31 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
32 | }
33 |
34 | {
35 | if (!_hydraScope.oS) {
36 | const oP = _hydra.o[0].constructor.prototype;
37 | oP.fboSettings = Array(2).fill({
38 | mag: "nearest",
39 | min: "nearest",
40 | width: width,
41 | height: height,
42 | format: "rgba",
43 | });
44 | oP.setFbos = function (fbo0, fbo1) {
45 | var colors = fbo1 ? [fbo0, fbo1] : [fbo0, fbo0];
46 | this.fboSettings = colors.map((x, i) => {
47 | return {
48 | ...this.fboSettings[i],
49 | width: width,
50 | height: height,
51 | ...x,
52 | };
53 | });
54 | this.fbos = this.fboSettings.map((x) =>
55 | this.regl.framebuffer({
56 | color: this.regl.texture(x),
57 | depthStencil: false,
58 | })
59 | );
60 | };
61 | oP.setClamp = function () {
62 | this.setFbos({ wrapS: "clamp", wrapT: "clamp" });
63 | };
64 | _hydraScope.oS = { outputs: window._hydra.o };
65 | _hydraScope.oS.setClamp = function () {
66 | this.outputs.forEach((x) => x.setClamp());
67 | };
68 | }
69 | _hydraScope.oS.setClamp();
70 | }
71 |
72 | // set all coord functions to no-wrap
73 | [
74 | {
75 | name: "scroll",
76 | type: "coord",
77 | inputs: [
78 | {
79 | type: "float",
80 | name: "scrollX",
81 | default: 0.5,
82 | },
83 | {
84 | type: "float",
85 | name: "scrollY",
86 | default: 0.5,
87 | },
88 | {
89 | type: "float",
90 | name: "speedX",
91 | default: 0,
92 | },
93 | {
94 | type: "float",
95 | name: "speedY",
96 | default: 0,
97 | },
98 | ],
99 | glsl: `_st.x += scrollX + time*speedX; _st.y += scrollY + time*speedY; return _st;`,
100 | },
101 | {
102 | name: "scrollX",
103 | type: "coord",
104 | inputs: [
105 | {
106 | type: "float",
107 | name: "scrollX",
108 | default: 0.5,
109 | },
110 | {
111 | type: "float",
112 | name: "speed",
113 | default: 0,
114 | },
115 | ],
116 | glsl: `_st.x += scrollX + time*speed; return _st;`,
117 | },
118 | {
119 | name: "modulateScrollX",
120 | type: "combineCoord",
121 | inputs: [
122 | {
123 | type: "float",
124 | name: "scrollX",
125 | default: 0.5,
126 | },
127 | {
128 | type: "float",
129 | name: "speed",
130 | default: 0,
131 | },
132 | ],
133 | glsl: `_st.x += _c0.r*scrollX + time*speed; return _st;`,
134 | },
135 | {
136 | name: "scrollY",
137 | type: "coord",
138 | inputs: [
139 | {
140 | type: "float",
141 | name: "scrollY",
142 | default: 0.5,
143 | },
144 | {
145 | type: "float",
146 | name: "speed",
147 | default: 0,
148 | },
149 | ],
150 | glsl: `_st.y += scrollY + time*speed; return _st;`,
151 | },
152 | {
153 | name: "modulateScrollY",
154 | type: "combineCoord",
155 | inputs: [
156 | {
157 | type: "float",
158 | name: "scrollY",
159 | default: 0.5,
160 | },
161 | {
162 | type: "float",
163 | name: "speed",
164 | default: 0,
165 | },
166 | ],
167 | glsl: ` _st.y += _c0.r*scrollY + time*speed; return _st;`,
168 | },
169 | ].forEach((x) => _hydra.synth.setFunction(x));
170 |
171 | // hydraWrap
172 |
173 | window.hydraWrap = {};
174 |
175 | hydraWrap.defaultList = [
176 | {
177 | name: "prev",
178 | type: "src",
179 | inputs: [],
180 | glsl: ` vec4 c0 = texture2D(prevBuffer, wrap(_st));
181 | //c0 *= step(abs(_st.x-0.5),0.5);
182 | //c0 *= step(abs(_st.t-0.5),0.5);
183 | return c0;`,
184 | },
185 | {
186 | name: "src",
187 | type: "src",
188 | inputs: [
189 | {
190 | type: "sampler2D",
191 | name: "tex",
192 | default: NaN,
193 | },
194 | ],
195 | glsl: ` vec4 c0 = texture2D(tex, wrap(_st));
196 | //c0 *= step(abs(_st.x-0.5),0.5);
197 | //c0 *= step(abs(_st.t-0.5),0.5);
198 | return c0;`,
199 | },
200 | {
201 | name: "wrap",
202 | type: "coord",
203 | inputs: [],
204 | glsl: `return wrap(_st);`,
205 | },
206 | ];
207 |
208 | hydraWrap.void = false;
209 |
210 | hydraWrap.generateFunctionListFromWrapper = function (wrapper) {
211 | return Array.from(hydraWrap.defaultList).map((_f) => {
212 | let f = Object.assign({}, _f);
213 | f.glsl = f.glsl.replace("wrap(_st)", wrapper);
214 | f.glsl = hydraWrap.void ? f.glsl.replaceAll("//c0", "c0") : f.glsl;
215 | return f;
216 | });
217 | };
218 |
219 | hydraWrap.wrappers = {
220 | wrap: "fract(_st)",
221 | nowrap: "_st",
222 | mirror: "-abs(fract(_st/2.0)*2.0-1.0)+1.0",
223 | };
224 |
225 | hydraWrap.currentWrapper = hydraWrap.wrappers.wrap;
226 |
227 | hydraWrap.setWrap = function () {
228 | hydraWrap.void = false;
229 | hydraWrap.currentWrapper = hydraWrap.wrappers.wrap;
230 | hydraWrap
231 | .generateFunctionListFromWrapper(hydraWrap.wrappers.wrap)
232 | .forEach((x) => _hydra.synth.setFunction(x));
233 | };
234 |
235 | hydraWrap.setRepeat = hydraWrap.setWrap;
236 |
237 | hydraWrap.setNoWrap = function () {
238 | hydraWrap.void = false;
239 | hydraWrap.currentWrapper = hydraWrap.wrappers.nowrap;
240 | hydraWrap
241 | .generateFunctionListFromWrapper(hydraWrap.wrappers.nowrap)
242 | .forEach((x) => _hydra.synth.setFunction(x));
243 | };
244 |
245 | hydraWrap.setClamp = hydraWrap.setNoWrap;
246 |
247 | hydraWrap.setMirror = function () {
248 | hydraWrap.void = false;
249 | hydraWrap.currentWrapper = hydraWrap.wrappers.mirror;
250 | hydraWrap
251 | .generateFunctionListFromWrapper(hydraWrap.wrappers.mirror)
252 | .forEach((x) => _hydra.synth.setFunction(x));
253 | };
254 |
255 | hydraWrap.setCustom = function (wrapper = "_st") {
256 | hydraWrap.void = false;
257 | hydraWrap.currentWrapper = wrapper;
258 | hydraWrap
259 | .generateFunctionListFromWrapper(wrapper)
260 | .forEach((x) => _hydra.synth.setFunction(x));
261 | };
262 |
263 | // setVoid should only be called after setting a wrapping mode
264 | hydraWrap.setVoid = function (to = true) {
265 | hydraWrap.void = to;
266 | hydraWrap
267 | .generateFunctionListFromWrapper(hydraWrap.currentWrapper)
268 | .forEach((x) => _hydra.synth.setFunction(x));
269 | };
270 |
271 | hydraWrap.setWrap();
272 |
--------------------------------------------------------------------------------
/hydra-arithmetics.js:
--------------------------------------------------------------------------------
1 | {
2 | const getHydra = function () {
3 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
4 | ? "editor"
5 | : window.atom?.packages
6 | ? "atom"
7 | : "idk";
8 | if (whereami === "editor") {
9 | return window.hydraSynth;
10 | }
11 | if (whereami === "atom") {
12 | return global.atom.packages.loadedPackages["atom-hydra"]
13 | .mainModule.main.hydra;
14 | }
15 | let _h = [
16 | window.hydraSynth,
17 | window._hydra,
18 | window.hydra,
19 | window.h,
20 | window.H,
21 | window.hy
22 | ].find(h => h?.regl);
23 | return _h;
24 | };
25 | window._hydra = getHydra();
26 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
27 | }
28 |
29 | {
30 | const gS = _hydraScope.osc().constructor.prototype;
31 |
32 | function wrapColorCombine(name, color, combine) {
33 | gS[name] = function (arg, ...args) {
34 | let isArgument =
35 | typeof arg == "number" ||
36 | typeof arg == "function" ||
37 | typeof arg == "string" ||
38 | arg.constructor.name == "Array";
39 | return isArgument
40 | ? this[color](arg)
41 | : args.length
42 | ? this[combine](arg, ...args)
43 | : this[combine](arg);
44 | };
45 | }
46 |
47 | {
48 | const noInputs = (
49 | "abs,sign,fract," +
50 | "sin,cos,tan,asin,acos,atan," +
51 | "exp,log,exp2,log2,sqrt,inversesqrt"
52 | ).split(",");
53 |
54 | noInputs.forEach((name) => {
55 | _hydra.synth.setFunction({
56 | name: "_" + name,
57 | type: "color",
58 | inputs: [],
59 | glsl: `return ${name}(_c0);`,
60 | });
61 | gS[name] = gS["_" + name];
62 | });
63 | }
64 |
65 | {
66 | const singleArgument = "mod,min,max,step,pow".split(",");
67 |
68 | singleArgument.forEach((name) => {
69 | _hydra.synth.setFunction({
70 | name: "_" + name,
71 | type: "combine",
72 | inputs: [],
73 | glsl: `return ${name}(_c0,_c1);`,
74 | });
75 | _hydra.synth.setFunction({
76 | name: "_" + name + "_single",
77 | type: "color",
78 | inputs: [{ name: "_in", type: "float", default: 1 }],
79 | glsl: `return ${name}(_c0,vec4(_in));`,
80 | });
81 | wrapColorCombine(name, "_" + name + "_single", "_" + name);
82 | });
83 | }
84 |
85 | _hydra.synth.setFunction({
86 | name: "_div",
87 | type: "combine",
88 | inputs: [],
89 | glsl: `return _c0 / _c1;`,
90 | });
91 | _hydra.synth.setFunction({
92 | name: "_div_single",
93 | type: "color",
94 | inputs: [{ name: "_in", type: "float", default: 1 }],
95 | glsl: `return _c0 / _in;`,
96 | });
97 | wrapColorCombine("div", "_div_single", "_div");
98 |
99 | _hydra.synth.setFunction({
100 | name: "_add",
101 | type: "combine",
102 | inputs: [{ type: "float", name: "amount", default: 1 }],
103 | glsl: `return _c0 + (_c1*amount);`,
104 | });
105 | _hydra.synth.setFunction({
106 | name: "_add_single",
107 | type: "color",
108 | inputs: [{ name: "_in", type: "float", default: 1 }],
109 | glsl: `return _c0 + _in;`,
110 | });
111 | wrapColorCombine("add", "_add_single", "_add");
112 |
113 | _hydra.synth.setFunction({
114 | name: "_sub",
115 | type: "combine",
116 | inputs: [{ type: "float", name: "amount", default: 1 }],
117 | glsl: `return _c0 - (_c1*amount);`,
118 | });
119 | _hydra.synth.setFunction({
120 | name: "_sub_single",
121 | type: "color",
122 | inputs: [{ name: "_in", type: "float", default: 1 }],
123 | glsl: `return _c0 - _in;`,
124 | });
125 | wrapColorCombine("sub", "_sub_single", "_sub");
126 |
127 | _hydra.synth.setFunction({
128 | name: "_mult",
129 | type: "combine",
130 | inputs: [{ type: "float", name: "amount", default: 1 }],
131 | glsl: `return _c0*(1.0-amount)+(_c0*_c1)*amount;`,
132 | });
133 | _hydra.synth.setFunction({
134 | name: "_mult_single",
135 | type: "color",
136 | inputs: [{ name: "_in", type: "float", default: 1 }],
137 | glsl: `return _c0 * _in;`,
138 | });
139 | wrapColorCombine("mult", "_mult_single", "_mult");
140 |
141 | gS.amp = gS._mult_single;
142 | gS.amplitude = gS.amp;
143 | gS.offset = gS._add_single;
144 | gS.off = gS.offset;
145 |
146 | _hydra.synth.setFunction({
147 | name: "bipolar",
148 | type: "color",
149 | inputs: [{ name: "amp", type: "float", default: 1 }],
150 | glsl: `return ((_c0 * 2.0) - 1.0) * amp;`,
151 | });
152 | _hydra.synth.setFunction({
153 | name: "unipolar",
154 | type: "color",
155 | inputs: [{ name: "amp", type: "float", default: 1 }],
156 | glsl: `return ((_c0 + 1.0) * 0.5) * amp;`,
157 | });
158 |
159 | _hydra.synth.setFunction({
160 | name: "range",
161 | type: "color",
162 | inputs: [
163 | { name: "_min", type: "float", default: 0 },
164 | { name: "_max", type: "float", default: 1 },
165 | ],
166 | glsl: `return _c0 * (_max - _min) + _min;`,
167 | });
168 | _hydra.synth.setFunction({
169 | name: "birange",
170 | type: "color",
171 | inputs: [
172 | { name: "_min", type: "float", default: 0 },
173 | { name: "_max", type: "float", default: 1 },
174 | ],
175 | glsl: `return ((_c0 + 1.0) * 0.5) * (_max - _min) + _min;`,
176 | });
177 | _hydra.synth.setFunction({
178 | name: "_clamp",
179 | type: "color",
180 | inputs: [
181 | { name: "_min", type: "float", default: 0 },
182 | { name: "_max", type: "float", default: 1 },
183 | ],
184 | glsl: `return clamp(_c0, _min, _max);`,
185 | });
186 | gS.clamp = gS._clamp;
187 |
188 | _hydra.synth.setFunction({
189 | name: "x",
190 | type: "src",
191 | inputs: [
192 | { name: "mult", type: "float", default: 1 },
193 | ],
194 | glsl: `return vec4(vec3(_st.x*mult),1.0);`,
195 | });
196 | _hydra.synth.setFunction({
197 | name: "y",
198 | type: "src",
199 | inputs: [
200 | { name: "mult", type: "float", default: 1 },
201 | ],
202 | glsl: `return vec4(vec3(_st.y*mult),1.0);`,
203 | });
204 | _hydra.synth.setFunction({
205 | name: "length",
206 | type: "src",
207 | inputs: [
208 | { name: "mult", type: "float", default: 1 },
209 | ],
210 | glsl: `return vec4(vec3(length(_st*mult)),1.0);`,
211 | });
212 | _hydra.synth.setFunction({
213 | name: "distance",
214 | type: "src",
215 | inputs: [
216 | { name: "px", type: "float", default: 0 },
217 | { name: "py", type: "float", default: 0 },
218 | ],
219 | glsl: `return vec4(vec3(length(_st,vec2(px,py))),1.0);`,
220 | });
221 |
222 | _hydra.synth.setFunction({
223 | name: "xCenter",
224 | type: "src",
225 | inputs: [
226 | { name: "mult", type: "float", default: 1 },
227 | ],
228 | glsl: `return vec4(vec3((0.5-_st.x)*mult),1.0);`,
229 | });
230 | _hydra.synth.setFunction({
231 | name: "yCenter",
232 | type: "src",
233 | inputs: [
234 | { name: "mult", type: "float", default: 1 },
235 | ],
236 | glsl: `return vec4(vec3((0.5-_st.y)*mult),1.0);`,
237 | });
238 | _hydra.synth.setFunction({
239 | name: "lengthCenter",
240 | type: "src",
241 | inputs: [
242 | { name: "mult", type: "float", default: 1 },
243 | ],
244 | glsl: `return vec4(vec3(length((vec2(0.5)-_st)*mult)),1.0);`,
245 | });
246 | _hydra.synth.setFunction({
247 | name: "distanceCenter",
248 | type: "src",
249 | inputs: [
250 | { name: "px", type: "float", default: 0 },
251 | { name: "py", type: "float", default: 0 },
252 | ],
253 | glsl: `return vec4(vec3(length(vec2(0.5)-_st,vec2(0.5)-vec2(px,py))),1.0);`,
254 | });
255 |
256 | }
257 |
--------------------------------------------------------------------------------
/doc/hydra-colorspaces.md:
--------------------------------------------------------------------------------
1 | # hydra-colorspaces
2 |
3 | The hydra-colorspaces extension adds lots of functions to work with color in many different colorspaces.
4 |
5 | ## Available colorspaces
6 |
7 | | Colorspace | Elements | Stands for | Range | Description |
8 | |-----------------|----------|------------|--------|---------------|
9 | | rgb | r,g,b,a | Red, Green, Blue, Alpha | [0;1] [0;1] [0;1] [0;1] | Good old RGBA
10 | | cmyk | c,m,y,k | Cyan, Magenta, Yellow, Key | [0;1] [0;1] [0;1] [0;1] | Substractive colorspace used in print
11 | | hsv | h,s,v | Hue, Saturation, Value (Brightness) | [0;1] [0;1] [0;1] | Cylindrical colorspace where saturation peaks when brightness is 1
12 | | hsl | h,s,l | Hue, Saturation, Lightness | [0;1] [0;1] [0;1] | Cylindrical colorspace where saturation peaks when lightness is 0.5
13 | | yuv | y,u,v | Luminance, Blue difference, Red difference | [0;1] [-0.5;+0.5] [-0.5;+0.5] | Color model used in PAL systems
14 | | yiq | y,i,q | Luminance, In-phase, Quadrature | [0;1] [-0.5;+0.5] [-0.5;+0.5] | Color model used in NTSC systems
15 |
16 | ## List of functions
17 |
18 | Here are all the functions written for quick reference, exemplified using the `hsv` colorspace and the `h` element, however these apply to any colorspace and any element within it:
19 |
20 | ```js
21 | // solid
22 | hsv(1,0.5,1,1).out()
23 | // color
24 | gradient().hsv(1,0.5,1).out()
25 | gradient().hsv.offset(.5,0,-.2).out()
26 | gradient().hsv.invert(1,0,1).out()
27 | gradient().hsv.to().out()
28 | gradient().hsv.from().out()
29 | // element specific
30 | gradient().hsv.h().out()
31 | gradient().hsv.hMult(2).out()
32 | gradient().hsv.hOffset(.2).out()
33 | gradient().hsv.hInvert().out()
34 | gradient().hsv.hSet(0.3).out()
35 | gradient().hsv.hFrom(osc()).out()
36 | gradient().hsv.hMultFrom(osc(),1.5).out()
37 | gradient().hsv.hOffsetFrom(noise(),0.2).out()
38 | gradient().hsv.hKey(0.2).out()
39 | gradient().hsv.hWith(x=>x.pixelate()).out()
40 | ```
41 |
42 | ## Syntax
43 |
44 | This extensions automatically defines functions for the different colorspaces, so listing them all wouldn't make sense. Instead of naming each colorspace, for the purpose of this documentation, I'll be generically referring to all color spaces as `cs`, and to **any** of their elements as `el`. For example, instead of `.cmyk.cOffset()`, which offsets the Cyan element in the CMYK colorspace, I'll write `.cs.elOffset()`.
45 |
46 | ### Arguments
47 |
48 | If you read `el` as the argument for a function, it means there's an argument for each element of the colorspace in order. For example, `cs(el,alpha)` would mean `yuv(y,u,v,alpha)` for that colorspace.
49 |
50 | ### About alpha
51 |
52 | Some functions add alpha as a last argument after the elements of the colorspace. This doesn't apply to RGBA, given it already has alpha in it. For example `cs(el=0, alpha=1)` means `rgb(r=0,g=0,b=0,a=1)`.
53 |
54 | ---
55 |
56 | ## Functions
57 |
58 | ### Solid colors
59 |
60 | **`cs( el = 0, alpha = 1 )`**
61 | * Example: `hsv(()=>time,1,1).out()`
62 | * Alias: `cs_solid()`
63 |
64 | These functions will act similarly to Hydra's `solid()` function, letting you write a particular color in the given colorspace and filling the screen with it.
65 |
66 | ---
67 |
68 | ### Multiply elements
69 |
70 | **`.cs( el = 1, alpha = 1 )`**
71 | * Example: `osc(20,.1,2).yuv(1,1,0).out()`
72 | * Alias: `.cs.color()`, `.cs_color()`
73 |
74 | These functions will act similarly to Hydra's `.color()` function, allowing you to multiply the value of each element in the colorspace.
75 |
76 | #### Multiply a specific element
77 |
78 | **`.cs.elMult( amt = 1 )`**
79 | * Example: `gradient().hsl.sMult(.8).out()`
80 | * Alias: `.cs_el_mult()`
81 |
82 | ---
83 |
84 | ### Offset elements
85 |
86 | **`.cs.offset( el = 0, alpha = 0 )`**
87 | * Example: `gradient().hsv.offset(.5,-.2,.5).out()`
88 | * Alias: `.cs_offset()`
89 |
90 | Offset an element by a given amount. Basically adds the number you give it to the corresponding element.
91 |
92 | #### Offset a specific element
93 |
94 | **`.cs.elOffset()`**
95 | * Example: `osc().yiq.qOffset(.2).out()`
96 | * Alias: `.cs_el_offset()`
97 |
98 | ---
99 |
100 | ### Invert elements
101 |
102 | **`.cs.invert( el = 1, alpha = 0 )`**
103 | * Example: `gradient().cmyk.invert(1,0,1,0).out()`
104 | * Alias: `.cs_invert()`
105 |
106 | Invert an element by a given amount. The argument sets interpolation between the original color and the inverted one, that's why the default for elements is 1 while alpha is 0. An inversion here means `1.0 - el` for most elements. For those elements with a bipolar range, inversion is done by calculating `0.0 - el` instead.
107 |
108 | #### Invert a specific element
109 |
110 | **`.cs.elInvert()`**
111 | * Example: `osc(5,.1,2).yiq.qInvert().out()`
112 | * Alias: `.cs_el_invert()`
113 |
114 | ---
115 |
116 | ### Converting to a given colorspace
117 |
118 | **`.cs.to()`**
119 | * Example: `gradient().cmyk.to().out()`
120 | * Alias: `.cs_to()`
121 |
122 | Converts the color values of the texture which calls the method to the given colorspace.
123 |
124 | ### Converting from a given colorspace to RGBA
125 |
126 | **`.cs.from()`**
127 | * Example: `gradient().add(solid(0,0,1)).hsv.from().out()`
128 | * Alias: `.cs_from()`
129 |
130 | Let's you convert back to RGBA, or interpret any color values as if they were from the given colorspace.
131 |
132 | ---
133 |
134 | ## Other element specific functions
135 |
136 | ### Retrieving an element
137 |
138 | **`.cs.el()`**
139 | * Example: `osc(40,.1,Math.PI/2).hsv.h().out()`
140 | * Alias: `.cs_el()`
141 |
142 | These functions will work in the same way as Hydra's `r()`, `b()`, `g()`, and `a()` functions. They will simply replicate the given element's value in all channels except alpha and return an opaque image.
143 |
144 | ---
145 |
146 | ### Setting an element
147 |
148 | **`.cs.elSet( value = 1 )`**
149 | * Example: `osc(8,.1,2).hsv.sSet(.5).out()`
150 | * Alias: `.cs_el_set()`
151 |
152 | Allows you to set the given element to a fixed value for all pixels. Shown in the example being used to set the saturation of a texture.
153 |
154 | ---
155 |
156 | ### Modulating an element by a given texture
157 |
158 | **Note:** All the modulating functions take only the first value from the texture, or in other words, the red channel. If you want to modulate by another element in the given texture, simply retrieve that element from the texture as shown just above.
159 |
160 | #### Setting by a given texture
161 |
162 | **`.cs.elFrom( texture , amt = 1 )`**
163 | * Example: `rgb(1,0,0).hsl.sFrom(osc(9)).out()`
164 | * Alias: `.cs_el_from()`
165 |
166 | Will set the value of the element to the value in the given texture. The `amt` argument allows you to interpolate between the original value for the element and the texture's value.
167 |
168 | #### Multiplying by a given texture
169 |
170 | **`.cs.elMultFrom( texture, amt = 1 )`**
171 | * Example: `gradient().hsl.sMultFrom(osc(9)).out()`
172 | * Alias: `.cs_el_mult_from()`
173 |
174 | Will multiply the given element's value by the given texture. The texture's value will be multiplied by the `amt` parameter.
175 |
176 | #### Offsetting by a given texture
177 |
178 | **`.cs.elOffsetFrom( texture, amt = 1 )`**
179 | * Example: `gradient().hsl.hOffsetFrom(noise(1,2),.2).out()`
180 | * Alias: `.cs_el_mult_from()`
181 |
182 | Will add the texture to the given value. The texture's value will be multiplied by the `amt` parameter.
183 |
184 | ---
185 |
186 | ### Keying by a given element
187 |
188 | **`.cs.elKey( topThreshold = 0.5 , topTolerance = 0.05 , bottomThreshold = 0 , bottomTolerance = 0 )`**
189 | * Example: `solid().layer(gradient(1).rgb.rKey(.5,0)).out()`
190 | * Alias: `.cs_el_key()`
191 |
192 | Similar to Hydra's `luma()`, but instead of keying by luminance, you can key by any element. THese functions will turn transparent any pixel where the given element isn't between the top threshold and the bottom threshold.
193 |
194 | **Note:** These functions work with straight alpha, so you might not see changes directly on screen unless you layer it over something else. Similarly to how `osc().color(1,1,1,0).out()` still appears on screen even though it should be completely transparent. If you are someone familiar with straight and premultiplied alpha, you might be interested to join the discussion in [this issue](https://github.com/hydra-synth/hydra-synth/issues/109) I've opened on the hydra-synth repo.
195 |
196 | ---
197 |
198 | ### Applying a transform to a given element
199 |
200 | **`.cs.elWith( f )`**
201 | * Example: `osc(10,.1,2).rotate().hsv.hWith(x=>x.pixelate(16,32)).out()`
202 | * Alias: `.cs_el_with()`
203 |
204 | Inspired by TidalCycles xWith functions, these functions allow you to apply a transform only to a given element. The `f` argument should be a function which receives a texture and returns a texture.
205 |
206 | These are basically syntactic sugar for `texture.cs.elFrom(cloneOfTexture.transform().el())`. This means that in order for these to work Hydra has to render the given texture twice, since its cloning it. So be very cautious about performance when using these.
207 |
--------------------------------------------------------------------------------
/hydra-abbreviations.js:
--------------------------------------------------------------------------------
1 | // hydra-abbreviations
2 | // diminutives for all the functions
3 |
4 | {
5 | const getHydra = function () {
6 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
7 | ? "editor"
8 | : window.atom?.packages
9 | ? "atom"
10 | : "idk";
11 | if (whereami === "editor") {
12 | return window.hydraSynth;
13 | }
14 | if (whereami === "atom") {
15 | return global.atom.packages.loadedPackages["atom-hydra"]
16 | .mainModule.main.hydra;
17 | }
18 | let _h = [
19 | window.hydraSynth,
20 | window._hydra,
21 | window.hydra,
22 | window.h,
23 | window.H,
24 | window.hy
25 | ].find(h => h?.regl);
26 | return _h;
27 | };
28 | window._hydra = getHydra();
29 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
30 | }
31 |
32 | {
33 | const gS = _hydraScope.osc().constructor.prototype;
34 |
35 | gS.bl = gS.blend;
36 | gS.bright = gS.brightness;
37 | gS.br = gS.brightness;
38 | gS.clr = gS.color;
39 | gS.c = gS.color;
40 | gS.clrm = gS.colorama;
41 | gS.cm = gS.colorama;
42 | gS.cntrst = gS.contrast;
43 | gS.ct = gS.contrast;
44 | gS.df = gS.diff;
45 | gS.invrt = gS.invert;
46 | gS.inv = gS.invert;
47 | gS.i = gS.invert;
48 | gS.kld = gS.kaleid;
49 | gS.k = gS.kaleid;
50 | gS.lyr = gS.layer;
51 | gS.ly = gS.layer;
52 | gS.lr = gS.layer;
53 | gS.l = gS.layer;
54 | gS.lm = gS.luma;
55 | gS.msk = gS.mask;
56 | gS.mod = gS.modulate;
57 | gS.m = gS.modulate;
58 | gS.modh = gS.modulateHue;
59 | gS.mh = gS.modulateHue;
60 | gS.mH = gS.modulateHue;
61 | gS.modk = gS.modulateKaleid;
62 | gS.mk = gS.modulateKaleid;
63 | gS.mK = gS.modulateKaleid;
64 | gS.modp = gS.modulatePixelate;
65 | gS.mp = gS.modulatePixelate;
66 | gS.mP = gS.modulatePixelate;
67 | gS.modrp = gS.modulateRepeat;
68 | gS.mrp = gS.modulateRepeat;
69 | gS.mRp = gS.modulateRepeat;
70 | gS.modrpx = gS.modulateRepeatX;
71 | gS.mrpx = gS.modulateRepeatX;
72 | gS.mRpx = gS.modulateRepeatX;
73 | gS.mRpX = gS.modulateRepeatX;
74 | gS.modrpy = gS.modulateRepeatY;
75 | gS.mrpy = gS.modulateRepeatY;
76 | gS.mRpy = gS.modulateRepeatY;
77 | gS.mRpY = gS.modulateRepeatY;
78 | gS.modr = gS.modulateRotate;
79 | gS.mr = gS.modulateRotate;
80 | gS.mR = gS.modulateRotate;
81 | gS.modrt = gS.modulateRotate;
82 | gS.mrt = gS.modulateRotate;
83 | gS.mRt = gS.modulateRotate;
84 | gS.modrot = gS.modulateRotate;
85 | gS.mrot = gS.modulateRotate;
86 | gS.mRot = gS.modulateRotate;
87 | gS.mods = gS.modulateScale;
88 | gS.ms = gS.modulateScale;
89 | gS.mS = gS.modulateScale;
90 | gS.modx = gS.modulateScrollX;
91 | gS.mx = gS.modulateScrollX;
92 | gS.mX = gS.modulateScrollX;
93 | gS.mody = gS.modulateScrollY;
94 | gS.my = gS.modulateScrollY;
95 | gS.mY = gS.modulateScrollY;
96 | gS.mlt = gS.mult;
97 | gS.ml = gS.mult;
98 | gS.mt = gS.mult;
99 | gS.pxlt = gS.pixelate;
100 | gS.px = gS.pixelate;
101 | gS.p = gS.pixelate;
102 | gS.pstr = gS.posterize;
103 | gS.ps = gS.posterize;
104 | gS.rpt = gS.repeat;
105 | gS.rp = gS.repeat;
106 | gS.rptx = gS.repeatX;
107 | gS.rpx = gS.repeatX;
108 | gS.rptX = gS.repeatX;
109 | gS.rpX = gS.repeatX;
110 | gS.rpty = gS.repeatY;
111 | gS.rpy = gS.repeatY;
112 | gS.rptY = gS.repeatY;
113 | gS.rpY = gS.repeatY;
114 | gS.rot = gS.rotate;
115 | gS.rt = gS.rotate;
116 | gS.strt = gS.saturate;
117 | gS.st = gS.saturate;
118 | gS.s = gS.scale;
119 | gS.sc = gS.scale;
120 | gS.scrll = gS.scroll;
121 | gS.xy = gS.scroll;
122 | gS.x = gS.scrollX;
123 | gS.y = gS.scrollY;
124 | gS.shft = gS.shift;
125 | gS.sh = gS.shift;
126 | gS.sb = gS.sub;
127 | gS.sm = gS.sum;
128 | gS.thrsh = gS.thresh;
129 | gS.thr = gS.thresh;
130 | gS.th = gS.thresh;
131 | gS.t = gS.thresh;
132 |
133 | gS.__proto__.o = gS.__proto__.out;
134 |
135 | _hydraScope.n = noise;
136 | _hydraScope.ns = noise;
137 | _hydraScope.vor = voronoi;
138 | _hydraScope.vr = voronoi;
139 | _hydraScope.v = voronoi;
140 | _hydraScope.shp = shape;
141 | _hydraScope.sh = shape;
142 | _hydraScope.grd = gradient;
143 | _hydraScope.gr = gradient;
144 | _hydraScope.gd = gradient;
145 | _hydraScope.s = solid;
146 | _hydraScope.sl = solid;
147 | _hydraScope.o = osc;
148 |
149 | // abbreviator
150 | // TODO: refactor this mess:
151 |
152 | window.Abbreviator = {
153 | abbreviations: {
154 | functions: {
155 | blend: "bl",
156 | bright: "br",
157 | color: "c",
158 | colorama: "cm",
159 | contrast: "ct",
160 | diff: "df",
161 | invert: "inv",
162 | kaleid: "k",
163 | layer: "l",
164 | luma: "lm",
165 | mask: "msk",
166 | modulate: "m",
167 | modulateHue: "mH",
168 | modulateKaleid: "mK",
169 | modulatePixelate: "mP",
170 | modulateRepeat: "mRp",
171 | modulateRepeatX: "mRpX",
172 | modulateRepeatY: "mRpY",
173 | modulateRotate: "mR",
174 | modulateScale: "mS",
175 | modulateScrollX: "mX",
176 | modulateScrollY: "mY",
177 | mult: "mlt",
178 | pixelate: "p",
179 | posterize: "ps",
180 | repeat: "rp",
181 | repeatX: "rpX",
182 | repeatY: "rpY",
183 | rotate: "rt",
184 | saturate: "st",
185 | scale: "sc",
186 | scroll: "xy",
187 | scrollX: "x",
188 | scrollY: "y",
189 | shift: "sh",
190 | sub: "sb",
191 | sum: "sm",
192 | thresh: "th",
193 | },
194 | sources: {
195 | noise: "ns",
196 | voronoi: "vr",
197 | shape: "sh",
198 | gradient: "grd",
199 | solid: "sl",
200 | },
201 | }, // here comes some ugly code:
202 | getKeyFromValue(object, value) {
203 | return Object.keys(object).find((key) => object[key] === value);
204 | },
205 | checkAndUnabbreviateSource(match, offset, string) {
206 | k = match.replace("(", "");
207 | replace =
208 | Abbreviator.getKeyFromValue(
209 | Abbreviator.abbreviations.sources,
210 | k
211 | ) + "(";
212 | if (offset == 0) return replace;
213 | pch = string[offset - 1];
214 | if ("\n\t;( ".includes(pch)) return replace;
215 | else return match;
216 | },
217 | checkAndUnabbreviateFunction(match, offset, string) {
218 | k = match.replace("(", "").replace(".", "");
219 | replace =
220 | "." +
221 | Abbreviator.getKeyFromValue(
222 | Abbreviator.abbreviations.functions,
223 | k
224 | ) +
225 | "(";
226 | if (offset == 0) return match;
227 | pch = string[offset - 1];
228 | if ("\n\t )".includes(pch)) return replace;
229 | else return match;
230 | },
231 | checkAndAbbreviateSource(match, offset, string) {
232 | k = match.replace("(", "");
233 | replace = Abbreviator.abbreviations.sources[k] + "(";
234 | if (offset == 0) return replace;
235 | pch = string[offset - 1];
236 | if ("\n\t;( ".includes(pch)) return replace;
237 | else return match;
238 | },
239 | checkAndAbbreviateFunction(match, offset, string) {
240 | k = match.replace("(", "").replace(".", "");
241 | replace = "." + Abbreviator.abbreviations.functions[k] + "(";
242 | if (offset == 0) return match;
243 | pch = string[offset - 1];
244 | if ("\n\t )".includes(pch)) return replace;
245 | else return match;
246 | },
247 | removeSpacing(code) {
248 | return code
249 | .replaceAll(" ", "")
250 | .replaceAll("\n", "")
251 | .replaceAll("\t", "");
252 | },
253 | abbreviate(code, noSpacing = false) {
254 | Object.keys(Abbreviator.abbreviations.functions).forEach((k) => {
255 | code = code.replaceAll(
256 | "." + k + "(",
257 | Abbreviator.checkAndAbbreviateFunction
258 | );
259 | });
260 | Object.keys(Abbreviator.abbreviations.sources).forEach((k) => {
261 | code = code.replaceAll(
262 | k + "(",
263 | Abbreviator.checkAndAbbreviateSource
264 | );
265 | });
266 | code = noSpacing ? Abbreviator.removeSpacing(code) : code;
267 | console.log(code);
268 | return code;
269 | },
270 | unabbreviate(code) {
271 | Object.keys(Abbreviator.abbreviations.sources).forEach((k) => {
272 | k = Abbreviator.abbreviations.sources[k];
273 | code = code.replaceAll(
274 | k + "(",
275 | Abbreviator.checkAndUnabbreviateSource
276 | );
277 | });
278 | Object.keys(Abbreviator.abbreviations.functions).forEach((k) => {
279 | k = Abbreviator.abbreviations.functions[k];
280 | code = code.replaceAll(
281 | "." + k + "(",
282 | Abbreviator.checkAndUnabbreviateFunction
283 | );
284 | });
285 | console.log(code);
286 | return code;
287 | },
288 | };
289 | window.abbreviate = Abbreviator.abbreviate.bind(Abbreviator);
290 | window.unabbreviate = Abbreviator.unabbreviate.bind(Abbreviator);
291 | }
292 |
--------------------------------------------------------------------------------
/old/hydra-blending-modes.js:
--------------------------------------------------------------------------------
1 | // blend modes
2 | // https://www.shadertoy.com/view/XdS3RW
3 | // https://www.w3.org/TR/compositing-1
4 | // https://raw.githubusercontent.com/samarthgulati/hydra-blockly/master/image-editing-glsl-functions.js
5 |
6 | console.log("hydra-blending-modes is deprecated, I recomment using hydra-blend instead")
7 |
8 | var blendmodes_glsl_fns = [
9 | // vec3 darken( vec3 s, vec3 d )
10 | // {
11 | // return min(s,d);
12 | // }
13 | {
14 | name: "darken",
15 | type: "combine",
16 | inputs: [],
17 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
18 | vec3 _c1a = _c1.rgb * _c1.a;
19 | return vec4(min(_c0a,_c1a), _c0.a);`
20 | },
21 |
22 | // vec3 multiply( vec3 s, vec3 d )
23 | // {
24 | // return s*d;
25 | // }
26 | {
27 | name: "multiply",
28 | type: "combine",
29 | inputs: [],
30 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
31 | vec3 _c1a = _c1.rgb * _c1.a;
32 | return vec4(_c0a * _c1a, _c0.a);`
33 | },
34 |
35 | // vec3 colorBurn( vec3 s, vec3 d )
36 | // {
37 | // return 1.0 - (1.0 - d) / s;
38 | // }
39 | {
40 | name: "colorBurn",
41 | type: "combine",
42 | inputs: [],
43 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
44 | vec3 _c1a = _c1.rgb * _c1.a;
45 | return vec4(1.0 - (1.0 - _c1a) / _c0a, _c0.a);`
46 | },
47 |
48 | // vec3 linearBurn( vec3 s, vec3 d )
49 | // {
50 | // return s + d - 1.0;
51 | // }
52 | {
53 | name: "linearBurn",
54 | type: "combine",
55 | inputs: [],
56 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
57 | vec3 _c1a = _c1.rgb * _c1.a;
58 | return vec4(_c0a + _c1a - 1.0, _c0.a);`
59 | },
60 |
61 | // vec3 darkerColor( vec3 s, vec3 d )
62 | // {
63 | // return (s.x + s.y + s.z < d.x + d.y + d.z) ? s : d;
64 | // }
65 | {
66 | name: "darkerColor",
67 | type: "combine",
68 | inputs: [],
69 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
70 | vec3 _c1a = _c1.rgb * _c1.a;
71 | return (_c0a.r + _c0a.g + _c0a.b < _c1a.r + _c1a.g + _c1a.b) ? vec4(_c0a, _c0.a) : vec4(_c1a, _c0.a);`
72 | },
73 |
74 | // vec3 lighten( vec3 s, vec3 d )
75 | // {
76 | // return max(s,d);
77 | // }
78 | {
79 | name: "lighten",
80 | type: "combine",
81 | inputs: [],
82 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
83 | vec3 _c1a = _c1.rgb * _c1.a;
84 | return vec4(max(_c0a,_c1a), _c0.a);`
85 | },
86 |
87 | // vec3 screen( vec3 s, vec3 d )
88 | // {
89 | // return s + d - s * d;
90 | // }
91 | {
92 | name: "screen",
93 | type: "combine",
94 | inputs: [],
95 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
96 | vec3 _c1a = _c1.rgb * _c1.a;
97 | return vec4(_c0a + _c1a - _c0a * _c1a, _c0.a);`
98 | },
99 |
100 | // vec3 colorDodge( vec3 s, vec3 d )
101 | // {
102 | // return d / (1.0 - s);
103 | // }
104 | {
105 | name: "colorDodge",
106 | type: "combine",
107 | inputs: [],
108 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
109 | vec3 _c1a = _c1.rgb * _c1.a;
110 | return _c0a == vec3(0.) ? vec4(0.) : _c1a == vec3(1.) ? vec4(1.) : vec4(_c1a / (1.0 - _c0a), _c0.a);`
111 | },
112 |
113 | // vec3 linearDodge( vec3 s, vec3 d )
114 | // {
115 | // return s + d;
116 | // }
117 | {
118 | name: "linearDodge",
119 | type: "combine",
120 | inputs: [],
121 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
122 | vec3 _c1a = _c1.rgb * _c1.a;
123 | return vec4(_c0a + _c1a, _c0.a);`
124 | },
125 |
126 | // vec3 lighterColor( vec3 s, vec3 d )
127 | // {
128 | // return (s.x + s.y + s.z > d.x + d.y + d.z) ? s : d;
129 | // }
130 | {
131 | name: "lighterColor",
132 | type: "combine",
133 | inputs: [],
134 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
135 | vec3 _c1a = _c1.rgb * _c1.a;
136 | return (_c0a.r + _c0a.g + _c0a.b > _c1a.r + _c1a.g + _c1a.b) ? vec4(_c0a, _c0.a) : vec4(_c1a, _c0.a);`
137 | },
138 |
139 | // float overlay( float s, float d )
140 | // {
141 | // return (d < 0.5) ? 2.0 * s * d : 1.0 - 2.0 * (1.0 - s) * (1.0 - d);
142 | // }
143 | // vec3 overlay( vec3 s, vec3 d )
144 | // {
145 | // vec3 c;
146 | // c.x = overlay(s.x,d.x);
147 | // c.y = overlay(s.y,d.y);
148 | // c.z = overlay(s.z,d.z);
149 | // return c;
150 | // }
151 | {
152 | name: "overlay",
153 | type: "combine",
154 | inputs: [],
155 | glsl: ` vec4 o;
156 | vec3 _c0a = _c0.rgb * _c0.a;
157 | vec3 _c1a = _c1.rgb * _c1.a;
158 | o.r = (_c1a.r < 0.5) ? 2.0 * _c0a.r * _c1a.r : 1.0 - 2.0 * (1.0 - _c0a.r) * (1.0 - _c1a.r);
159 | o.g = (_c1a.g < 0.5) ? 2.0 * _c0a.g * _c1a.g : 1.0 - 2.0 * (1.0 - _c0a.g) * (1.0 - _c1a.g);
160 | o.b = (_c1a.b < 0.5) ? 2.0 * _c0a.b * _c1a.b : 1.0 - 2.0 * (1.0 - _c0a.b) * (1.0 - _c1a.b);
161 | o.a = _c0.a;
162 | return o;`
163 | },
164 |
165 | // float softLight( float s, float d )
166 | // {
167 | // return (s < 0.5) ? d - (1.0 - 2.0 * s) * d * (1.0 - d)
168 | // : (d < 0.25) ? d + (2.0 * s - 1.0) * d * ((16.0 * d - 12.0) * d + 3.0)
169 | // : d + (2.0 * s - 1.0) * (sqrt(d) - d);
170 | // }
171 | // vec3 softLight( vec3 s, vec3 d )
172 | // {
173 | // vec3 c;
174 | // c.x = softLight(s.x,d.x);
175 | // c.y = softLight(s.y,d.y);
176 | // c.z = softLight(s.z,d.z);
177 | // return c;
178 | // }
179 | {
180 | name: "softLight",
181 | type: "combine",
182 | inputs: [],
183 | glsl: ` vec4 c;
184 | vec3 _c0a = _c0.rgb * _c0.a;
185 | vec3 _c1a = _c1.rgb * _c1.a;
186 | c.r = (_c0a.r < 0.5) ? _c1a.r - (1.0 - 2.0 * _c0a.r) * _c1a.r * (1.0 - _c1a.r) : (_c1a.r < 0.25) ? _c1a.r * ((16.0 * _c1a.r - 12.0) * _c1a.r + 4.0) : _c1a.r + (2.0 * _c0a.r - 1.0) * (sqrt(_c1a.r) - _c1a.r);
187 | c.g = (_c0a.g < 0.5) ? _c1a.g - (1.0 - 2.0 * _c0a.g) * _c1a.g * (1.0 - _c1a.g) : (_c1a.g < 0.25) ? _c1a.g * ((16.0 * _c1a.g - 12.0) * _c1a.g + 4.0) : _c1a.g + (2.0 * _c0a.g - 1.0) * (sqrt(_c1a.g) - _c1a.g);
188 | c.b = (_c0a.b < 0.5) ? _c1a.b - (1.0 - 2.0 * _c0a.b) * _c1a.b * (1.0 - _c1a.b) : (_c1a.b < 0.25) ? _c1a.b * ((16.0 * _c1a.b - 12.0) * _c1a.b + 4.0) : _c1a.b + (2.0 * _c0a.b - 1.0) * (sqrt(_c1a.b) - _c1a.b);
189 | c.a = _c0.a;
190 | //(_c1a.a < 0.5) ? _c0a.a - (1.0 - 2.0 * _c1a.a) * _c0a.a * (1.0 - _c0a.a) : (_c0a.a < 0.25) ? _c0a.a * ((16.0 * _c0a.a - 12.0) * _c0a.a + 4.0) : _c0a.a + (2.0 * _c1a.a - 1.0) * (sqrt(_c0a.a) - _c0a.a);
191 | return c;`
192 | },
193 |
194 | // float hardLight( float s, float d )
195 | // {
196 | // return (s < 0.5) ? 2.0 * s * d : 1.0 - 2.0 * (1.0 - s) * (1.0 - d);
197 | // }
198 |
199 | // vec3 hardLight( vec3 s, vec3 d )
200 | // {
201 | // vec3 c;
202 | // c.x = hardLight(s.x,d.x);
203 | // c.y = hardLight(s.y,d.y);
204 | // c.z = hardLight(s.z,d.z);
205 | // return c;
206 | // }
207 |
208 | {
209 | name: "hardLight",
210 | type: "combine",
211 | inputs: [],
212 | glsl: ` vec4 c;
213 | vec3 _c0a = _c0.rgb * _c0.a;
214 | vec3 _c1a = _c1.rgb * _c1.a;
215 | c.r = (_c0a.r < 0.5) ? 2.0 * _c0a.r * _c1a.r : 1.0 - 2.0 * (1.0 - _c0a.r) * (1.0 - _c1a.r);
216 | c.g = (_c0a.g < 0.5) ? 2.0 * _c0a.g * _c1a.g : 1.0 - 2.0 * (1.0 - _c0a.g) * (1.0 - _c1a.g);
217 | c.b = (_c0a.b < 0.5) ? 2.0 * _c0a.b * _c1a.b : 1.0 - 2.0 * (1.0 - _c0a.b) * (1.0 - _c1a.b);
218 | c.a = _c0.a;
219 | return c;`
220 | },
221 |
222 | // float vividLight( float s, float d )
223 | // {
224 | // return (s < 0.5) ? 1.0 - (1.0 - d) / (2.0 * s) : d / (2.0 * (1.0 - s));
225 | // }
226 |
227 | // vec3 vividLight( vec3 s, vec3 d )
228 | // {
229 | // vec3 c;
230 | // c.x = vividLight(s.x,d.x);
231 | // c.y = vividLight(s.y,d.y);
232 | // c.z = vividLight(s.z,d.z);
233 | // return c;
234 | // }
235 |
236 | {
237 | name: "vividLight",
238 | type: "combine",
239 | inputs: [],
240 | glsl: ` vec4 c;
241 | vec3 _c0a = _c0.rgb * _c0.a;
242 | vec3 _c1a = _c1.rgb * _c1.a;
243 | c.r = (_c0a.r < 0.5) ? 1.0 - (1.0 - _c1a.r) / (2.0 * _c0a.r) : _c1a.r / (2.0 * (1.0 - _c0a.r));
244 | c.g = (_c0a.g < 0.5) ? 1.0 - (1.0 - _c1a.g) / (2.0 * _c0a.g) : _c1a.g / (2.0 * (1.0 - _c0a.g));
245 | c.b = (_c0a.b < 0.5) ? 1.0 - (1.0 - _c1a.b) / (2.0 * _c0a.b) : _c1a.b / (2.0 * (1.0 - _c0a.b));
246 | c.a = _c0.a;
247 | return c;`
248 | },
249 |
250 | // vec3 linearLight( vec3 s, vec3 d )
251 | // {
252 | // return 2.0 * s + d - 1.0;
253 | // }
254 |
255 | {
256 | name: "linearLight",
257 | type: "combine",
258 | inputs: [],
259 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
260 | vec3 _c1a = _c1.rgb * _c1.a;
261 | return vec4(2.0 * _c0a + _c1a - 1.0, _c0.a);`
262 | },
263 |
264 | // float pinLight( float s, float d )
265 | // {
266 | // return (2.0 * s - 1.0 > d) ? 2.0 * s - 1.0 : (s < 0.5 * d) ? 2.0 * s : d;
267 | // }
268 |
269 | // vec3 pinLight( vec3 s, vec3 d )
270 | // {
271 | // vec3 c;
272 | // c.x = pinLight(s.x,d.x);
273 | // c.y = pinLight(s.y,d.y);
274 | // c.z = pinLight(s.z,d.z);
275 | // return c;
276 | // }
277 |
278 | {
279 | name: "pinLight",
280 | type: "combine",
281 | inputs: [],
282 | glsl: ` vec4 c;
283 | vec3 _c0a = _c0.rgb * _c0.a;
284 | vec3 _c1a = _c1.rgb * _c1.a;
285 | c.r = (2.0 * _c0a.r - 1.0 > _c1a.r) ? 2.0 * _c0a.r - 1.0 : (_c0a.r < 0.5 * _c1a.r) ? 2.0 * _c0a.r : _c1a.r;
286 | c.g = (2.0 * _c0a.g - 1.0 > _c1a.g) ? 2.0 * _c0a.g - 1.0 : (_c0a.g < 0.5 * _c1a.g) ? 2.0 * _c0a.g : _c1a.g;
287 | c.b = (2.0 * _c0a.b - 1.0 > _c1a.b) ? 2.0 * _c0a.b - 1.0 : (_c0a.b < 0.5 * _c1a.b) ? 2.0 * _c0a.b : _c1a.b;
288 | c.a = _c0.a;
289 | return c;`
290 | },
291 |
292 | // vec3 hardMix( vec3 s, vec3 d )
293 | // {
294 | // return floor(s + d);
295 | // }
296 |
297 | {
298 | name: "hardMix",
299 | type: "combine",
300 | inputs: [],
301 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
302 | vec3 _c1a = _c1.rgb * _c1.a;
303 | return vec4(floor(_c0a + _c1a), _c0.a);`
304 | },
305 |
306 | // vec3 difference( vec3 s, vec3 d )
307 | // {
308 | // return abs(d - s);
309 | // }
310 |
311 | {
312 | name: "difference",
313 | type: "combine",
314 | inputs: [],
315 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
316 | vec3 _c1a = _c1.rgb * _c1.a;
317 | return vec4(abs(_c1a - _c0a), _c0.a);`
318 | },
319 |
320 | // vec3 exclusion( vec3 s, vec3 d )
321 | // {
322 | // return s + d - 2.0 * s * d;
323 | // }
324 | {
325 | name: "exclusion",
326 | type: "combine",
327 | inputs: [],
328 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
329 | vec3 _c1a = _c1.rgb * _c1.a;
330 | return vec4(_c0a + _c1a - 2.0 * _c0a * _c1a, _c0.a);`
331 | },
332 |
333 | // vec3 subtract( vec3 s, vec3 d )
334 | // {
335 | // return s - d;
336 | // }
337 | {
338 | name: "subtract",
339 | type: "combine",
340 | inputs: [],
341 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
342 | vec3 _c1a = _c1.rgb * _c1.a;
343 | return vec4(_c0a - _c1a, _c0.a);`
344 | },
345 |
346 | // vec3 divide( vec3 s, vec3 d )
347 | // {
348 | // return s / d;
349 | // }
350 | {
351 | name: "divide",
352 | type: "combine",
353 | inputs: [],
354 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
355 | vec3 _c1a = _c1.rgb * _c1.a;
356 | return vec4(_c0a / _c1a, _c0.a);`
357 | },
358 |
359 | // // rgb<-->hsv functions by Sam Hocevar
360 | // // http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl
361 | // vec3 rgb2hsv(vec3 c)
362 | // {
363 | // vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
364 | // vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
365 | // vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
366 |
367 | // float d = q.x - min(q.w, q.y);
368 | // float e = 1.0e-10;
369 | // return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
370 | // }
371 |
372 | // vec3 hsv2rgb(vec3 c)
373 | // {
374 | // vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
375 | // vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
376 | // return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
377 | // }
378 |
379 | // vec3 hue( vec3 s, vec3 d )
380 | // {
381 | // d = rgb2hsv(d);
382 | // d.x = rgb2hsv(s).x;
383 | // return hsv2rgb(d);
384 | // }
385 | {
386 | name: "hueBlend",
387 | type: "combine",
388 | inputs: [],
389 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
390 | vec3 _c1a = _c1.rgb * _c1.a;
391 | _c1a = _rgbToHsv(_c1a);
392 | _c1a.x = _rgbToHsv(_c0a).x;
393 | return vec4(_hsvToRgb(_c1a), _c0.a);`
394 | },
395 |
396 | // vec3 color( vec3 s, vec3 d )
397 | // {
398 | // s = rgb2hsv(s);
399 | // s.z = rgb2hsv(d).z;
400 | // return hsv2rgb(s);
401 | // }
402 |
403 | {
404 | name: "colorBlend",
405 | type: "combine",
406 | inputs: [],
407 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
408 | vec3 _c1a = _c1.rgb * _c1.a;
409 | _c0a = _rgbToHsv(_c0a);
410 | _c0a.z = _rgbToHsv(_c1a).z;
411 | return vec4(_hsvToRgb(_c0a), _c0.a);`
412 | },
413 |
414 | // vec3 saturation( vec3 s, vec3 d )
415 | // {
416 | // d = rgb2hsv(d);
417 | // d.y = rgb2hsv(s).y;
418 | // return hsv2rgb(d);
419 | // }
420 |
421 | {
422 | name: "saturationBlend",
423 | type: "combine",
424 | inputs: [],
425 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
426 | vec3 _c1a = _c1.rgb * _c1.a;
427 | _c1a = _rgbToHsv(_c1a);
428 | _c1a.y = _rgbToHsv(_c0a).y;
429 | return vec4(_hsvToRgb(_c1a), _c0.a);`
430 | },
431 |
432 | // vec3 luminosity( vec3 s, vec3 d )
433 | // {
434 | // float dLum = dot(d, vec3(0.3, 0.59, 0.11));
435 | // float sLum = dot(s, vec3(0.3, 0.59, 0.11));
436 | // float lum = sLum - dLum;
437 | // vec3 c = d + lum;
438 | // float minC = min(min(c.x, c.y), c.z);
439 | // float maxC = max(max(c.x, c.y), c.z);
440 | // if(minC < 0.0) return sLum + ((c - sLum) * sLum) / (sLum - minC);
441 | // else if(maxC > 1.0) return sLum + ((c - sLum) * (1.0 - sLum)) / (maxC - sLum);
442 | // else return c;
443 | // }
444 | {
445 | name: "luminosityBlend",
446 | type: "combine",
447 | inputs: [],
448 | glsl: ` vec3 _c0a = _c0.rgb * _c0.a;
449 | vec3 _c1a = _c1.rgb * _c1.a;
450 | float dLum = dot(_c1a, vec3(0.3, 0.59, 0.11));
451 | float sLum = dot(_c0a, vec3(0.3, 0.59, 0.11));
452 | float lum = sLum - dLum;
453 | vec3 c = _c1a + lum;
454 | float minC = min(min(c.x, c.y), c.z);
455 | float maxC = max(max(c.x, c.y), c.z);
456 | if(minC < 0.0) return vec4(sLum + ((c - sLum) * sLum) / (sLum - minC), _c0.a);
457 | else if(maxC > 1.0) return vec4(sLum + ((c - sLum) * (1.0 - sLum)) / (maxC - sLum), _c0.a);
458 | else return vec4(c, _c0.a);`
459 | }
460 | ];
461 |
462 | blendmodes_glsl_fns.forEach((fn) => {setFunction(fn)})
463 | blendmodes_list = blendmodes_glsl_fns.map(a => a.name)
464 |
465 | console.log(blendmodes_list)
466 |
--------------------------------------------------------------------------------
/hydra-convolutions.js:
--------------------------------------------------------------------------------
1 | {
2 | const getHydra = function () {
3 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
4 | ? "editor"
5 | : window.atom?.packages
6 | ? "atom"
7 | : "idk";
8 | if (whereami === "editor") {
9 | return window.hydraSynth;
10 | }
11 | if (whereami === "atom") {
12 | return global.atom.packages.loadedPackages["atom-hydra"]
13 | .mainModule.main.hydra;
14 | }
15 | let _h = [
16 | window.hydraSynth,
17 | window._hydra,
18 | window.hydra,
19 | window.h,
20 | window.H,
21 | window.hy
22 | ].find(h => h?.regl);
23 | return _h;
24 | };
25 | window._hydra = getHydra();
26 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
27 | }
28 |
29 | {
30 | function generateJumps(height, width) {
31 | const middleY = Math.floor(height / 2);
32 | const middleX = Math.floor(width / 2);
33 |
34 | let jumpTable = Array.from({ length: height }, () => []);
35 |
36 | for (let y = 0; y < height; y++) {
37 | const posY = (middleY - y).toFixed(1);
38 | for (let x = 0; x < width; x++) {
39 | const posX = (middleX - x).toFixed(1);
40 | const vec2 = `vec2(${posX}, ${posY})`;
41 | jumpTable[y].push(vec2);
42 | }
43 | }
44 |
45 | return jumpTable.flat();
46 | }
47 |
48 | function processElement(element){
49 | return (typeof element === 'string') ? `(${element})` : element.toFixed(9);
50 | }
51 |
52 | function generateWeights(kernel) {
53 | const weights = kernel.flat().map(processElement);
54 | const hasParameters = weights.some(x => x.includes("k"));
55 | weights.hasParameters = hasParameters;
56 | return weights;
57 | }
58 |
59 | function generateConvolutionFunction(obj, settings) {
60 | const name = obj.name + settings.nameSufix;
61 | const kernel = obj.kernel;
62 | const multiplier = processElement(obj.multiplier || 1);
63 | const [height, width] = [kernel.length, kernel[0].length];
64 | const weights = generateWeights(kernel);
65 | const jumps = generateJumps(height, width);
66 | const hasParameters = weights.hasParameters;
67 |
68 | const { prefix, newLine, sufix } = settings;
69 |
70 | let code = prefix + "\n";
71 |
72 | weights.forEach((weight, i) => {
73 | const jump = jumps[i];
74 | if (weight == 0) return;
75 | const line = newLine(weight, jump);
76 | code += line + "\n";
77 | });
78 |
79 | code += sufix(multiplier);
80 |
81 | const inputs = [
82 | { name: '_tex0', type: 'sampler2D', default: o0 },
83 | { name: 'jump', type: 'float', default: 1 },
84 | { name: 'amp', type: 'float', default: 1 }
85 | ];
86 |
87 | if (hasParameters) {
88 | inputs.splice(1, 0, { name: 'k', type: 'float', default: 1 });
89 | }
90 |
91 | const func = {
92 | name,
93 | type: "src",
94 | inputs,
95 | glsl: code
96 | };
97 |
98 | return func;
99 | }
100 |
101 | function generateConvolutionFunctionRegular(obj) {
102 | const regularSettings = {
103 | nameSufix: "",
104 | prefix: "vec3 outputColor = vec3(0.0); vec2 res = resolution.xy;",
105 | newLine: (weight, jump) => `outputColor += (${weight}) * texture2D(_tex0, _st + (${jump} * jump / res)).rgb;`,
106 | sufix: (multiplier)=> `return vec4(outputColor * ${multiplier} * amp, texture2D(_tex0, _st).a);`
107 | };
108 | return generateConvolutionFunction(obj, regularSettings);
109 | }
110 |
111 | function generateConvolutionFunctionForLuma(obj) {
112 | const ySettings = {
113 | nameSufix: "Luma",
114 | prefix: "float outputLuma = 0.0; vec2 res = resolution.xy;",
115 | newLine: (weight, jump) => `outputLuma += (${weight}) * _luminance(texture2D(_tex0, _st + (${jump} * jump / res)).rgb);`,
116 | sufix: (multiplier) => `return vec4(vec3(outputLuma * ${multiplier} * amp), texture2D(_tex0, _st).a);`
117 | };
118 | return generateConvolutionFunction(obj, ySettings);
119 | }
120 |
121 | function generateConvolutionFunctionForY(obj) {
122 | const ySettings = {
123 | nameSufix: "OnY",
124 | prefix: `
125 | mat3 rgb2yuv = mat3(0.2126, 0.7152, 0.0722, -0.09991, -0.33609, 0.43600, 0.615, -0.5586, -0.05639);
126 | mat3 yuv2rgb = mat3(1.0, 0.0, 1.28033, 1.0, -0.21482, -0.38059, 1.0, 2.12798, 0.0);
127 | float outputY = 0.0;
128 | vec2 res = resolution.xy;
129 | `,
130 | newLine: (weight, jump) => `outputY += (${weight}) * (texture2D(_tex0, _st + (${jump} * jump / res)).rgb * rgb2yuv).x;`,
131 | sufix: (multiplier)=> `
132 | vec4 outputColor = texture2D(_tex0, _st);
133 | vec3 yuv = outputColor.rgb * rgb2yuv;
134 | yuv.x = outputY * ${multiplier};
135 | outputColor.rgb = yuv * yuv2rgb * amp;
136 | return outputColor;
137 | `
138 | };
139 | return generateConvolutionFunction(obj, ySettings);
140 | }
141 |
142 | function generateConvolutionFunctionForUV(obj) {
143 | const uvSettings = {
144 | nameSufix: "OnUV",
145 | prefix: `
146 | mat3 rgb2yuv = mat3(0.2126, 0.7152, 0.0722, -0.09991, -0.33609, 0.43600, 0.615, -0.5586, -0.05639);
147 | mat3 yuv2rgb = mat3(1.0, 0.0, 1.28033, 1.0, -0.21482, -0.38059, 1.0, 2.12798, 0.0);
148 | vec2 outputUV = vec2(0.0);
149 | vec2 res = resolution.xy;
150 | `,
151 | newLine: (weight, jump) => `outputUV += (${weight}) * (texture2D(_tex0, _st + (${jump} * jump / res)).rgb * rgb2yuv).yz;`,
152 | sufix: (multiplier) => `
153 | vec4 outputColor = texture2D(_tex0, _st);
154 | vec3 yuv = outputColor.rgb * rgb2yuv;
155 | yuv.yz = outputUV * ${multiplier};
156 | outputColor.rgb = yuv * yuv2rgb * amp;
157 | return outputColor;
158 | `
159 | };
160 | return generateConvolutionFunction(obj, uvSettings);
161 | }
162 |
163 | function generateConvolutionFunctionForIQ(obj) {
164 | const iqSettings = {
165 | nameSufix: "OnIQ",
166 | prefix: `
167 | mat3 rgb2yiq = mat3(0.299, 0.587, 0.114, 0.5959, -0.2746, -0.3213, 0.2115, -0.5227, 0.3112);
168 | mat3 yiq2rgb = mat3(1.0, 0.956, 0.619, 1.0, -0.272, -0.647, 1.0, -1.106, 1.703);
169 | vec2 outputIQ = vec2(0.0);
170 | vec2 res = resolution.xy;
171 | `,
172 | newLine: (weight, jump) => `outputIQ += (${weight}) * (texture2D(_tex0, _st + (${jump} * jump / res)).rgb * rgb2yiq).yz;`,
173 | sufix: (multiplier) => `
174 | vec4 outputColor = texture2D(_tex0, _st);
175 | vec3 yiq = outputColor.rgb * rgb2yiq;
176 | yiq.yz = outputIQ * ${multiplier};
177 | outputColor.rgb = yiq * yiq2rgb * amp;
178 | return outputColor;
179 | `
180 | };
181 | return generateConvolutionFunction(obj, iqSettings);
182 | }
183 |
184 | function setConvolutionFunction(definition) {
185 | const definitions = [
186 | generateConvolutionFunctionRegular(definition),
187 | generateConvolutionFunctionForLuma(definition),
188 | generateConvolutionFunctionForY(definition),
189 | generateConvolutionFunctionForUV(definition),
190 | generateConvolutionFunctionForIQ(definition)
191 | ]
192 | definitions.forEach(_hydra.synth.setFunction);
193 | }
194 | _hydraScope.setConvolutionFunction = setConvolutionFunction;
195 |
196 | }
197 |
198 | {
199 | // convolution kernel lists
200 | const convolutionKernels = [
201 | {
202 | name: "sharpen",
203 | kernel: [
204 | [0, "-k", 0],
205 | ["-k", "(4.0*k)+1.0", "-k"],
206 | [0, "-k", 0]
207 | ]
208 | },
209 | {
210 | name: "sharpenMore",
211 | kernel: [
212 | ["-k", "-k", "-k"],
213 | ["-k", "(8.0*k)+1.0", "-k"],
214 | ["-k", "-k", "-k"]
215 | ]
216 | },
217 | {
218 | name: "lineSharpen",
219 | kernel: [
220 | ["-k", "(2.0*k)+1.0", "-k"]
221 | ]
222 | },
223 | {
224 | name: "emboss",
225 | kernel: [
226 | ["-2.0*k", "-k", 0],
227 | ["-k", 1, "k"],
228 | [0, "k", "2.0*k"]
229 | ]
230 | },
231 | {
232 | name: "blur",
233 | kernel: [
234 | [1, 2, 1],
235 | [2, 4, 2],
236 | [1, 2, 1]
237 | ],
238 | multiplier: (1 / 16)
239 | },
240 | {
241 | name: "blur5",
242 | kernel: [
243 | [1, 4, 7, 4, 1],
244 | [4, 16, 26, 16, 4],
245 | [7, 26, 41, 26, 7],
246 | [4, 16, 26, 16, 4],
247 | [1, 4, 7, 4, 1]
248 | ],
249 | multiplier: (1 / 273)
250 | },
251 | {
252 | name: "blur7",
253 | kernel: [
254 | [0, 0, 1, 2, 1, 0, 0],
255 | [0, 3, 13, 22, 13, 3, 0],
256 | [1, 13, 59, 97, 59, 13, 1],
257 | [2, 22, 97, 159, 97, 22, 2],
258 | [1, 13, 59, 97, 59, 13, 1],
259 | [0, 3, 13, 22, 13, 3, 0],
260 | [0, 0, 1, 2, 1, 0, 0]
261 | ],
262 | multiplier: (1 / 1003)
263 | },
264 | {
265 | name: "boxBlur",
266 | kernel: [
267 | [1, 1, 1],
268 | [1, 1, 1],
269 | [1, 1, 1]
270 | ],
271 | multiplier: (1 / 9)
272 | },
273 | {
274 | name: "boxBlur5",
275 | kernel: [
276 | [1, 1, 1, 1, 1],
277 | [1, 1, 1, 1, 1],
278 | [1, 1, 1, 1, 1],
279 | [1, 1, 1, 1, 1],
280 | [1, 1, 1, 1, 1]
281 | ],
282 | multiplier: (1 / 25)
283 | },
284 | {
285 | name: "horizontalBlur",
286 | kernel: [
287 | [0, 0, 0, 0, 0],
288 | [0, 0, 0, 0, 0],
289 | [1, 1, 1, 1, 1],
290 | [0, 0, 0, 0, 0],
291 | [0, 0, 0, 0, 0]
292 | ],
293 | multiplier: (1 / 5)
294 | },
295 | {
296 | name: "verticalBlur",
297 | kernel: [
298 | [0, 0, 1, 0, 0],
299 | [0, 0, 1, 0, 0],
300 | [0, 0, 1, 0, 0],
301 | [0, 0, 1, 0, 0],
302 | [0, 0, 1, 0, 0]
303 | ],
304 | multiplier: (1 / 5)
305 | },
306 | {
307 | name: "diagonalBlur",
308 | kernel: [
309 | [0, 0, 0, 0, 1],
310 | [0, 0, 0, 1, 0],
311 | [0, 0, 1, 0, 0],
312 | [0, 1, 0, 0, 0],
313 | [1, 0, 0, 0, 0]
314 | ],
315 | multiplier: (1 / 5)
316 | },
317 | {
318 | name: "diagonalBlur2",
319 | kernel: [
320 | [1, 0, 0, 0, 0],
321 | [0, 1, 0, 0, 0],
322 | [0, 0, 1, 0, 0],
323 | [0, 0, 0, 1, 0],
324 | [0, 0, 0, 0, 1]
325 | ],
326 | multiplier: (1 / 5)
327 | },
328 | {
329 | name: "lineBlur",
330 | kernel: [
331 | [1, 2, 1]
332 | ],
333 | multiplier: (1 / 4)
334 | },
335 | {
336 | name: "lineBlur5",
337 | kernel: [
338 | [7, 26, 41, 26, 7]
339 | ],
340 | multiplier: (1 / 107)
341 | },
342 | {
343 | name: "sobelY",
344 | kernel: [
345 | [ 1, 2, 1],
346 | [ 0, 0, 0],
347 | [-1, -2, -1]
348 | ]
349 | },
350 | {
351 | name: "sobelX",
352 | kernel: [
353 | [-1, 0, 1],
354 | [-2, 0, 2],
355 | [-1, 0, 1]
356 | ]
357 | },
358 | {
359 | name: "sobelDiagonal",
360 | kernel: [
361 | [ 2, 1, 0],
362 | [ 1, 0, -1],
363 | [ 0, -1, -2]
364 | ]
365 | },
366 | {
367 | name: "sobelDiagonal2",
368 | kernel: [
369 | [ 0, 1, 2],
370 | [-1, 0, 1],
371 | [-2, -1, 0]
372 | ]
373 | },
374 | {
375 | name: "prewittY",
376 | kernel: [
377 | [ 1, 1, 1],
378 | [ 0, 0, 0],
379 | [-1, -1, -1]
380 | ]
381 | },
382 | {
383 | name: "prewittX",
384 | kernel: [
385 | [-1, 0, 1],
386 | [-1, 0, 1],
387 | [-1, 0, 1]
388 | ]
389 | },
390 | {
391 | name: "prewittDiagonal",
392 | kernel: [
393 | [ 1, 1, 0],
394 | [ 1, 0, -1],
395 | [ 0, -1, -1]
396 | ]
397 | },
398 | {
399 | name: "prewittDiagonal2",
400 | kernel: [
401 | [ 0, 1, 1],
402 | [-1, 0, 1],
403 | [-1, -1, 0]
404 | ]
405 | },
406 | {
407 | name: "edge",
408 | kernel: [
409 | [-1, -1, -1],
410 | [-1, 8, -1],
411 | [-1, -1, -1]
412 | ]
413 | }
414 | ]
415 |
416 | convolutionKernels.forEach(_hydraScope.setConvolutionFunction)
417 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # hyper-hydra
2 |
3 | Extensions for [Hydra](https://github.com/ojack/hydra) focusing on usability.
4 |
5 | ## How to load extensions
6 |
7 | You can load extensions into Hydra with the following syntax:
8 |
9 | ```js
10 | await loadScript("https://hyper-hydra.glitch.me/hydra-src.js")
11 | await loadScript("https://hyper-hydra.glitch.me/hydra-wrap.js")
12 |
13 | osc().out()
14 | ```
15 |
16 | ---
17 |
18 | ## List of extensions
19 |
20 | Order is merely alphabetical
21 |
22 | ### hydra-abbreviations
23 |
24 | Write very small hydra code.
25 |
26 | [source](./hydra-abbreviations.js) / [url](https://hyper-hydra.glitch.me/hydra-abbreviations.js)
27 |
28 | ```js
29 | o(10, 0.1, 1.2).bl(ns(3)).df(sh(4, 0.6).rt(0, 0.1)).out()
30 | ```
31 | [open in hydra!](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtYWJicmV2aWF0aW9ucy5qcyUyMiklMEElMEFvKDEwJTJDJTIwMC4xJTJDJTIwMS4yKS5ibChucygzKSkuZGYoc2goNCUyQyUyMDAuNikucnQoMCUyQyUyMDAuMSkpLm91dCgp)
32 |
33 | ---
34 |
35 | ### hydra-arithmetics
36 |
37 | All the functions you needed to make complex visual arithmetics, easily.
38 |
39 | [docs](./doc/hydra-arithmetics.md) / [url](https://hyper-hydra.glitch.me/hydra-arithmetics.js)
40 |
41 | ```js
42 | osc(10,.1,2)
43 | .mod(gradient().asin().cos())
44 | .step(noise(2).unipolar().div(o0))
45 | .blend(o0,.2)
46 | .out()
47 | ```
48 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtYXJpdGhtZXRpY3MuanMlMjIpJTBBJTBBb3NjKDEwJTJDLjElMkMyKSUwQSUwOS5tb2QoZ3JhZGllbnQoKS5hc2luKCkuY29zKCkpJTBBJTA5LnN0ZXAobm9pc2UoMikudW5pcG9sYXIoKS5kaXYobzApKSUwQSUwOS5ibGVuZChvMCUyQy4yKSUwQSUwOS5vdXQoKQ%3D%3D)
49 |
50 | ---
51 |
52 | ### hydra-arrays
53 |
54 | Extends the functionality of arrays in Hydra, letting you operate between different arrays and generate new ones.
55 |
56 | [docs](./doc/hydra-arrays.md) / [url](https://hyper-hydra.glitch.me/hydra-arrays.js)
57 |
58 | ```js
59 | gradient().diff(o0)
60 | .hue([0,2,3,8].div(10).addWrap([0.2,0.1]).smooth())
61 | .rotate(Array.run(8).mult(Math.PI*2/8))
62 | .add(shape(64,.02)
63 | .scrollX(Array.random(16,-0.4,0.4).smooth())
64 | .scrollY(Array.random(16,-0.4,0.4).smooth()))
65 | .blend(o0,.6)
66 | .out()
67 | bpm = 50
68 | ```
69 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtYXJyYXlzLmpzJTIyKSUwQSUwQWdyYWRpZW50KCklMEElMDkuZGlmZihvMCklMEElMDkuaHVlKCU1QjAlMkMyJTJDMyUyQzglNUQuZGl2KDEwKS5hZGRXcmFwKCU1QjAuMiUyQzAuMSU1RCkuc21vb3RoKCkpJTBBJTA5LnJvdGF0ZShBcnJheS5ydW4oOCkubXVsdChNYXRoLlBJKjIlMkY4KSklMEElMDkuYWRkKCUwQSUyMCUyMCUwOSUwOXNoYXBlKDY0JTJDLjAyKSUwQSUyMCUyMCUwOSUwOSUwOS5zY3JvbGxYKEFycmF5LnJhbmRvbSgxNiUyQy0wLjQlMkMwLjQpLnNtb290aCgpKSUwQSUyMCUyMCUwOSUwOSUwOS5zY3JvbGxZKEFycmF5LnJhbmRvbSgxNiUyQy0wLjQlMkMwLjQpLnNtb290aCgpKSUwQSUwOSklMEElMDkuYmxlbmQobzAlMkMuNiklMEElMDkub3V0KCklMEFicG0lMjAlM0QlMjA1MA%3D%3D)
70 |
71 | ---
72 |
73 | ### hydra-blend
74 |
75 | Adds most blending modes you know from raster image softwares. Ideal for compositing.
76 |
77 | [docs](./doc/hydra-blend.md) / [url](https://hyper-hydra.glitch.me/hydra-blend.js)
78 |
79 | ```js
80 | osc(30)
81 | .screen(noise(3,1).pm())
82 | .linearBurn(gradient(1).hue(.3))
83 | .out()
84 | ```
85 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtYmxlbmQuanMlMjIpJTBBJTBBb3NjKDMwKSUwQSUwOS5zY3JlZW4obm9pc2UoMyUyQzEpLnBtKCkpJTBBJTA5LmxpbmVhckJ1cm4oZ3JhZGllbnQoMSkuaHVlKC4zKSklMEElMDkub3V0KCk%3D)
86 |
87 | ---
88 |
89 | ### hydra-canvas
90 |
91 | Let's you easily control Hydra's canvas.
92 |
93 | [docs](./doc/hydra-canvas.md) / [url](https://hyper-hydra.glitch.me/hydra-canvas.js)
94 |
95 | ```js
96 | setResolution(256,256)
97 | canvas.setRelativeSize(2)
98 | canvas.setAlign("right")
99 | canvas.setLinear()
100 |
101 | solid(1).diff(o0).scale(.5).diff(noise(2,0.4)).out()
102 | ```
103 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtY2FudmFzLmpzJTIyKSUwQSUwQXNldFJlc29sdXRpb24oMjU2JTJDMjU2KSUwQWNhbnZhcy5zZXRSZWxhdGl2ZVNpemUoMiklMEFjYW52YXMuc2V0QWxpZ24oJTIycmlnaHQlMjIpJTBBY2FudmFzLnNldExpbmVhcigpJTBBJTBBc29saWQoMSkuZGlmZihvMCkuc2NhbGUoLjUpLmRpZmYobm9pc2UoMiUyQzAuNCkpLm91dCgp)
104 |
105 | ---
106 |
107 | ### hydra-colorspaces
108 |
109 | All the function you might need to work with color in different colorspaces such as CMYK, HSV, YUV, etc.
110 |
111 | [docs](./doc/hydra-colorspaces.md) / [url](https://hyper-hydra.glitch.me/hydra-colorspaces.js)
112 |
113 | ```js
114 | gradient().rgb.aSet(0)
115 | .cmyk.from()
116 | .hsv.hOffsetFrom(noise(1,1),.3)
117 | .yuv(1,.5)
118 | .out()
119 | ```
120 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtY29sb3JzcGFjZXMuanMlMjIpJTBBJTBBZ3JhZGllbnQoKS5yZ2IuYVNldCgwKSUwQSUyMCUyMCUwOS5jbXlrLmZyb20oKSUwQSUwOS5oc3YuaE9mZnNldEZyb20obm9pc2UoMSUyQzEpJTJDLjMpJTBBJTA5Lnl1digxJTJDLjUpJTBBJTA5Lm91dCgp)
121 |
122 | ---
123 |
124 | ### hydra-debug
125 |
126 | **WARNING:** doesn't work in atom / pulsar
127 |
128 | Adds a `.debug()` function that allows you to easily read the fragment shader of your sketch and test changes in real time.
129 |
130 | [docs](./doc/hydra-debug.md) / [url](https://hyper-hydra.glitch.me/hydra-debug.js)
131 |
132 | ```js
133 | osc().rotate().debug(o0)
134 | ```
135 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtZGVidWcuanMlMjIpJTBBJTBBb3NjKCkucm90YXRlKCkub3V0KCklMjAlMkYlMkYlMjB0cnklMjB0byUyMCU2MGRlYnVnJTYwJTIwbWUlMjAhISUwQSUwQSUyRiUyRiUyMG9zYygpLnJvdGF0ZSgpLmRlYnVnKG8wKQ%3D%3D)
136 |
137 | ---
138 |
139 | ### hydra-fractals
140 |
141 | Adds some functions that when feedbacked are useful for creating fractals. Thanks to [Kali](https://www.shadertoy.com/user/Kali) for the idea.
142 |
143 | [docs](./doc/hydra-fractals.md) / [url](https://hyper-hydra.glitch.me/hydra-fractals.js)
144 |
145 | ```js
146 | src(o0)
147 | .scale(.75)
148 | .add(noise(2,1),.4)
149 | .invert()
150 | .inversion()
151 | .mirrorX2()
152 | .blend(o0,.3)
153 | .out()
154 | ```
155 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtZnJhY3RhbHMuanMlMjIpJTBBYXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtb3V0cHV0cy5qcyUyMiklMEElMEFvUy5zZXRMaW5lYXIoKSUwQSUwQXNyYyhvMCklMEElMDkuc2NhbGUoLjc1KSUwQSUwOS5hZGQobm9pc2UoMiUyQzEpJTJDLjQpJTBBJTA5LmludmVydCgpJTBBJTA5LmludmVyc2lvbigpJTBBJTA5Lm1pcnJvclgyKCklMEElMDkuYmxlbmQobzAlMkMuMyklMEElMDkub3V0KCk%3D)
156 |
157 | ---
158 |
159 | ### hydra-gif
160 |
161 | **WARNING:** doesn't work on instance mode as of now
162 |
163 | Let's you load `.gif` files into Hydra.
164 |
165 | [docs](./doc/hydra-gif.md) / [url](https://hyper-hydra.glitch.me/hydra-gif.js)
166 |
167 | ```js
168 | s0.initGif('https://i.giphy.com/media/kZqbBT64ECtjy/giphy.gif')
169 |
170 | src(s0)
171 | .out()
172 | ```
173 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtZ2lmLmpzJTIyKSUwQSUwQXMwLmluaXRHaWYoJ2h0dHBzJTNBJTJGJTJGaS5naXBoeS5jb20lMkZtZWRpYSUyRmtacWJCVDY0RUN0anklMkZnaXBoeS5naWYnKSUwQSUwQXNyYyhzMCkuc2NhbGUoMSUyQy42KSUwQSUwOS5vdXQoKQ%3D%3D)
174 |
175 | ---
176 |
177 | ### hydra-glsl
178 |
179 | Write GLSL code directly in your patches.
180 |
181 | [docs](./doc/hydra-glsl.md) / [url](https://hyper-hydra.glitch.me/hydra-glsl.js)
182 |
183 | ```js
184 | glsl('vec4(sin(uv.x*i0+(time*i1*vec3(i2,i2*2.,i2*3.))),1.0)',16,2,.3)
185 | .glslColor('vec4(c0.brg-(sin(c0.b)*i0),1.)',()=>Math.cos(time))
186 | .out()
187 | ```
188 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtZ2xzbC5qcyUyMiklMEElMEFnbHNsKCd2ZWM0KHNpbih1di54KmkwJTJCKHRpbWUqaTEqdmVjMyhpMiUyQ2kyKjIuJTJDaTIqMy4pKSklMkMxLjApJyUyQzE2JTJDMiUyQy4zKSUwQSUwOS5nbHNsQ29sb3IoJ3ZlYzQoYzAuYnJnLShzaW4oYzAuYikqaTApJTJDMS4pJyUyQygpJTNEJTNFTWF0aC5jb3ModGltZSkpJTBBJTA5Lm91dCgp)
189 |
190 | ---
191 |
192 | ### hydra-gradientmap
193 |
194 | Create gradients with css colors and use them for gradient mapping.
195 |
196 | [url](https://hyper-hydra.glitch.me/hydra-gradientmap.js)
197 |
198 | ```js
199 | const myGradient = createGradient("#000", "#0bf", "red", "white");
200 |
201 | osc(30,.05).kaleid(720).scale(1,()=>innerHeight/innerWidth)
202 | .lookupX(myGradient)
203 | .out()
204 | ```
205 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlkcmEtZXh0ZW5zaW9ucy5nbGl0Y2gubWUlMkZoeWRyYS1ncmFkaWVudHMuanMlMjIpJTBBJTBBY29uc3QlMjBteUdyYWRpZW50JTIwJTNEJTIwY3JlYXRlR3JhZGllbnQoJTIyJTIzMDAwJTIyJTJDJTIwJTIyJTIzMGJmJTIyJTJDJTIwJTIycmVkJTIyJTJDJTIwJTIyd2hpdGUlMjIpJTNCJTBBJTIwJTBBb3NjKDMwJTJDLjA1KS5rYWxlaWQoNzIwKS5zY2FsZSgxJTJDKCklM0QlM0Vpbm5lckhlaWdodCUyRmlubmVyV2lkdGgpJTBBJTA5Lmxvb2t1cFgobXlHcmFkaWVudCklMEElMDkub3V0KCklMEElMjAlMEFzcmMobXlHcmFkaWVudCkub3V0KG8xKSUwQSUwQXJlbmRlcigp)
206 |
207 | ---
208 |
209 | ### hydra-mouse
210 |
211 | Replaces Hydra's standard `mouse` object adding useful properties.
212 |
213 | [docs](./doc/hydra-mouse.md) / [url](https://hyper-hydra.glitch.me/hydra-mouse.js)
214 |
215 | ```js
216 | noise(1)
217 | .add(shape(64,.01,.2).scrollX(()=>mouse.posx).scrollY(()=>mouse.posy))
218 | .out()
219 | ```
220 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtbW91c2UuanMlMjIpJTBBJTBBbm9pc2UoMSklMEElMDkuYWRkKHNoYXBlKDY0JTJDLjAxJTJDLjIpLnNjcm9sbFgoKCklM0QlM0Vtb3VzZS5wb3N4KS5zY3JvbGxZKCgpJTNEJTNFbW91c2UucG9zeSkpJTBBJTA5Lm91dCgp)
221 |
222 | ---
223 |
224 | ### hydra-outputs
225 |
226 | Change the properties of Hydra's outputs' framebuffers. Most importantly: try linear interpolation.
227 |
228 | [docs](./doc/hydra-outputs.md) / [url](https://hyper-hydra.glitch.me/hydra-outputs.js)
229 |
230 | ```js
231 | o1.setLinear()
232 |
233 | src(o1)
234 | .layer(osc(30,.2,1).mask(shape(4,.1,0)))
235 | .scale(1.01).rotate(.01)
236 | .out(o1)
237 | ```
238 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtb3V0cHV0cy5qcyUyMiklMEElMEFvMC5zZXROZWFyZXN0KCklMEFvMS5zZXRMaW5lYXIoKSUwQSUwQXNyYyhvMCklMEElMjAubGF5ZXIob3NjKDMwJTJDLjIlMkMxKS5tYXNrKHNoYXBlKDQlMkMuMSUyQzApKSklMEElMjAuc2NhbGUoMS4wMSkucm90YXRlKC4wMSklMEElMjAub3V0KG8wKSUwQSUwQXNyYyhvMSklMEElMjAubGF5ZXIob3NjKDMwJTJDLjIlMkMxKS5tYXNrKHNoYXBlKDQlMkMuMSUyQzApKSklMEElMjAuc2NhbGUoMS4wMSkucm90YXRlKC4wMSklMEElMjAub3V0KG8xKSUwQSUwQXJlbmRlcigp)
239 |
240 | ---
241 |
242 | ### hydra-pip
243 |
244 | Adds a function to toggle picture-in-picture. Note that colors might look a bit washed out since this extension uses hydra's canvas' MediaStream.
245 |
246 | [url](https://hyper-hydra.glitch.me/hydra-pip.js)
247 |
248 | ```js
249 | osc().out()
250 |
251 | hydraPictureInPicture() // alias: hydraPip()
252 | ```
253 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtcGlwLmpzJTIyKSUwQSUwQW9zYyg0MCUyQy4wOSUyQzEuNSklMEElMjAlMjAlMjAuZGlmZihvc2MoMjApLmx1bWEoKSklMEEub3V0KCklMEElMEElMkYlMkYlMjBoeWRyYVBpcCgpJTNC)
254 |
255 | ---
256 |
257 | ### hydra-pixels
258 |
259 | Retrieve pixel values from Hydra's outputs.
260 |
261 | [docs](./doc/hydra-pixels.md) / [url](https://hyper-hydra.glitch.me/hydra-pixels.js)
262 |
263 | ```js
264 | osc(40,.09,1.5)
265 | .diff(osc(20).luma())
266 | .color(1,1,()=>1+pixel[0]/255)
267 | .out()
268 |
269 | update = ()=> {
270 | pixel = o0.read(width/2,height/2) // center of the screen
271 | }
272 | ```
273 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtcGl4ZWxzLmpzJTIyKSUwQSUwQW9zYyg0MCUyQy4wOSUyQzEuNSklMEElMjAlMjAlMjAuZGlmZihvc2MoMjApLmx1bWEoKSklMEElMjAlMjAlMjAuY29sb3IoMSUyQzElMkMoKSUzRCUzRTElMkJwaXhlbCU1QjAlNUQlMkYyNTUpJTBBLm91dCgpJTBBJTBBdXBkYXRlJTIwJTNEJTIwKCklM0QlM0UlMjAlN0IlMEElMjAlMjBwaXhlbCUyMCUzRCUyMG8wLnJlYWQod2lkdGglMkYyJTJDaGVpZ2h0JTJGMiklMjAlMkYlMkYlMjBjZW50ZXIlMjBvZiUyMHRoZSUyMHNjcmVlbiUwQSU3RA%3D%3D)
274 |
275 | ---
276 |
277 | ### hydra-src
278 |
279 | Adds `srcAbs` and `srcRel` functions. `srcAbs` will act as `src()` but will show the source with its original width and height on screen. `scrRel` will act as `src()` but will mantain the source's aspect ratio. Works great with [hydra-wrap](#hydra-wrap). There's also `srcMask`, `srcAbsMask` and `srcAbsMark` which will mask out the wrapping.
280 |
281 | [url](https://hyper-hydra.glitch.me/hydra-src.js)
282 |
283 | ```js
284 | src(o0)
285 | .scale(1.01)
286 | .colorama(-.02).brightness(-.2)
287 | .blend(o0,.8)
288 | .layer(srcAbs(s0).luma(.4,.1))
289 | .out()
290 | ```
291 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtc3JjLmpzJTIyKSUwQSUwQXMwLmluaXRJbWFnZSgnaHR0cHMlM0ElMkYlMkZ1cGxvYWQud2lraW1lZGlhLm9yZyUyRndpa2lwZWRpYSUyRmNvbW1vbnMlMkYyJTJGMjUlMkZIeWRyYS1Gb3RvLmpwZycpJTBBJTBBc3JjKG8wKSUwQSUwOS5zY2FsZSgxLjAxKSUwQSUyMCUyMCUwOS5jb2xvcmFtYSgtLjAyKS5icmlnaHRuZXNzKC0uMiklMEElMjAlMjAlMDkuYmxlbmQobzAlMkMuOCklMEElMDkubGF5ZXIoc3JjQWJzKHMwKS5sdW1hKC40JTJDLjEpKSUwQSUwOS5vdXQoKQ%3D%3D)
292 |
293 | ---
294 |
295 | ### hydra-swizzle
296 |
297 | Replicates the swizzling functionality from GLSL.
298 |
299 | [docs](./doc/hydra-swizzle.md) / [url](https://hyper-hydra.glitch.me/hydra-swizzle.js)
300 |
301 | ```js
302 | gradient(1).gbg
303 | .layer(osc(30,.1,2).bggr)
304 | .layer(gradient().r.mask(shape(2)))
305 | .out()
306 | ```
307 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtc3dpenpsZS5qcyUyMiklMEElMEFncmFkaWVudCgxKS5nYmclMEElMDkubGF5ZXIob3NjKDMwJTJDLjElMkMyKS5iZ2dyKSUwQSUwOS5sYXllcihncmFkaWVudCgpLnIubWFzayhzaGFwZSgyKSkpJTBBJTA5Lm91dCgp)
308 |
309 | ---
310 |
311 | ### hydra-tap
312 |
313 | Adds a tap control for bpm and basic envelopes. Inspired by Resolume.
314 |
315 | [docs](./doc/hydra-tap.md) / [url](https://hyper-hydra.glitch.me/hydra-tap.js)
316 |
317 | ```js
318 | osc(30,.01,beats(1)).out()
319 |
320 | osc().rotate(beats_(2).curve(-3)).out()
321 |
322 | osc().scale(beats(1).curve(2).range(1,2)).out()
323 |
324 | // Ctrl + Space Bar for tapping
325 | // Ctrl + , (Comma) for re-sync
326 | ```
327 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtdGFwLmpzJTIyKSUwQSUwQW9zYygzMCUyQy4wMSUyQ2JlYXRzKDEpKS5vdXQoKSUwQSUwQW9zYygpLnJvdGF0ZShiZWF0c18oMikuY3VydmUoLTMpKS5vdXQoKSUwQSUwQW9zYygpLnNjYWxlKGJlYXRzKDEpLmN1cnZlKDIpLnJhbmdlKDElMkMyKSkub3V0KCklMEElMEElMkYlMkYlMjBDdHJsJTIwJTJCJTIwU3BhY2UlMjBCYXIlMjBmb3IlMjB0YXBwaW5nJTBBJTJGJTJGJTIwQ3RybCUyMCUyQiUyMCUyQyUyMChDb21tYSklMjBmb3IlMjByZS1zeW5j)
328 |
329 | ---
330 |
331 | ### hydra-text
332 |
333 | Adds a text generator to Hydra
334 |
335 | [docs](./doc/hydra-text.md) / [url](https://hyper-hydra.glitch.me/hydra-text.js)
336 |
337 | ```js
338 | hydraText.font = "serif"
339 | hydraText.lineWidth = "2%"
340 | str = " hydra_! "
341 | solid(1,.2)
342 | .blend(src(o0).scale(1.02).colorama(.02))
343 | .layer(text(str))
344 | .diff(strokeText(str).modulateScale(noise(1,1), .4))
345 | .out()
346 | ```
347 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtdGV4dC5qcyUyMiklMEElMEFoeWRyYVRleHQuZm9udCUyMCUzRCUyMCUyMnNlcmlmJTIyJTBBaHlkcmFUZXh0LmxpbmVXaWR0aCUyMCUzRCUyMCUyMjIlMjUlMjIlMEFzdHIlMjAlM0QlMjAlMjIlMjBoeWRyYV8hJTIwJTIyJTBBc29saWQoMSUyQy4yKSUwQSUwOS5ibGVuZChzcmMobzApLnNjYWxlKDEuMDIpLmNvbG9yYW1hKC4wMikpJTBBJTA5LmxheWVyKHRleHQoc3RyKSklMEElMDkuZGlmZihzdHJva2VUZXh0KHN0cikubW9kdWxhdGVTY2FsZShub2lzZSgxJTJDMSklMkMlMjAuNCkpJTBBJTA5Lm91dCgp)
348 |
349 | ---
350 |
351 | ### hydra-vec4
352 |
353 | Adds wrapper functions that allow you to construct vec4's like you would in GLSL.
354 |
355 | [docs](./doc/hydra-vec4.md) / [url](https://hyper-hydra.glitch.me/hydra-vec4.js)
356 |
357 | ```js
358 | noise()
359 | .mult( vec4( vec3(0.5) , 1 ) )
360 | .add( vec4( [0.5,0].smooth() ) )
361 | .layer(
362 | vec4( vec3( [0, 1, 0.5] , vec2( ()=>time%1 ) ) , 1)
363 | .mask(shape(4))
364 | )
365 | .out()
366 | ```
367 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtdmVjNC5qcyUyMiklMEElMEFub2lzZSgpJTBBJTA5Lm11bHQoJTIwdmVjNCglMjB2ZWMzKDAuNSklMjAlMkMlMjAxJTIwKSUyMCklMEElMjAlMjAlMDkuYWRkKCUyMHZlYzQoJTIwJTVCMC41JTJDMCU1RC5zbW9vdGgoKSUyMCklMjApJTBBJTA5LmxheWVyKCUwQSUwOSUwOXZlYzQoJTIwdmVjMyglMjAlNUIwJTJDJTIwMSUyQyUyMDAuNSU1RCUyMCUyQyUyMHZlYzIoJTIwKCklM0QlM0V0aW1lJTI1MSUyMCklMjApJTIwJTJDJTIwMSklMEElMjAlMjAlMDklMDklMDkubWFzayhzaGFwZSg0KSklMEElMDkpJTBBJTIwJTIwJTA5Lm91dCgp)
368 |
369 | ---
370 |
371 | ### hydra-wrap
372 |
373 | Change how Hydra wraps textures, and control the wrapping of generators.
374 |
375 | [docs](./doc/hydra-wrap.md) / [url](https://hyper-hydra.glitch.me/hydra-wrap.js)
376 |
377 | ```js
378 | hydraWrap.setMirror()
379 |
380 | src(o0)
381 | .layer(osc().rotate().mask(shape(4,1,0)))
382 | .scale(.5)
383 | .blend(noise(),.2)
384 | .out()
385 | ```
386 | [open in hydra](https://hydra.ojack.xyz/?code=YXdhaXQlMjBsb2FkU2NyaXB0KCUyMmh0dHBzJTNBJTJGJTJGaHlwZXItaHlkcmEuZ2xpdGNoLm1lJTJGaHlkcmEtd3JhcC5qcyUyMiklMEElMEFoeWRyYVdyYXAuc2V0TWlycm9yKCklMEElMEFzcmMobzApJTBBJTA5LmxheWVyKG9zYygpLnJvdGF0ZSgpLm1hc2soc2hhcGUoNCUyQzElMkMwKSkpJTBBJTA5LnNjYWxlKC41KSUwQSUwOS5ibGVuZChub2lzZSgpJTJDLjIpJTBBJTA5Lm91dCgp)
387 |
388 | ---
389 |
390 | ## Also check:
391 |
392 | * [`extra-shaders-for-hydra`](https://gitlab.com/metagrowing/extra-shaders-for-hydra) : another really useful repo of hydra extensions made by Thomas Jourdan
393 | * [`hydra-midi`](https://github.com/arnoson/hydra-midi) : a super complete midi extension for hydra, made by Arnno Schlipf.
394 | * [`hydra-antlia`](https://github.com/geikha/hydra-antlia) : my extension of hydra for colors, geometry and interactivity.
395 |
--------------------------------------------------------------------------------
/hydra-colorspaces.js:
--------------------------------------------------------------------------------
1 | {
2 | const getHydra = function () {
3 | const whereami = window.location?.href?.includes("hydra.ojack.xyz")
4 | ? "editor"
5 | : window.atom?.packages
6 | ? "atom"
7 | : "idk";
8 | if (whereami === "editor") {
9 | return window.hydraSynth;
10 | }
11 | if (whereami === "atom") {
12 | return global.atom.packages.loadedPackages["atom-hydra"]
13 | .mainModule.main.hydra;
14 | }
15 | let _h = [
16 | window.hydraSynth,
17 | window._hydra,
18 | window.hydra,
19 | window.h,
20 | window.H,
21 | window.hy
22 | ].find(h => h?.regl);
23 | return _h;
24 | };
25 | window._hydra = getHydra();
26 | window._hydraScope = _hydra.sandbox.makeGlobal ? window : _hydra.synth;
27 | }
28 |
29 | window.gS = _hydraScope.osc().constructor.prototype;
30 |
31 | {
32 | const hcs = {};
33 |
34 | hcs.colorspaces = [
35 | {
36 | name: "rgb",
37 | elems: ["r", "g", "b", "a"],
38 | to: "r = _r; g = _g; b = _b; a = _a;",
39 | from: "_r = r; _g = g; _b = b; _a = a;",
40 | },
41 | {
42 | name: "cmyk",
43 | elems: ["c", "m", "y", "k"],
44 | to: `
45 | k = 1.0-max(_r,max(_g,_b));
46 | c = (1.0-_r-k) / (1.0-k);
47 | m = (1.0-_g-k) / (1.0-k);
48 | y = (1.0-_b-k) / (1.0-k);
49 | `,
50 | from: `
51 | _r = (1.0-c)*(1.0-k);
52 | _g = (1.0-m)*(1.0-k);
53 | _b = (1.0-y)*(1.0-k);
54 | `,
55 | },
56 | {
57 | name: "hsv",
58 | elems: ["h", "s", "v"],
59 | to: `
60 | vec3 _hsv = _rgbToHsv(vec3(_r,_g,_b));
61 | h = _hsv.x; s = _hsv.y; v = _hsv.z;
62 | `,
63 | from: `
64 | vec3 _rgb = _hsvToRgb(vec3(h,s,v));
65 | _r = _rgb.r; _g = _rgb.g; _b = _rgb.b;
66 | `,
67 | },
68 | {
69 | name: "hsl",
70 | elems: ["h", "s", "l"],
71 | to: `
72 | vec3 _hsv = _rgbToHsv(vec3(_r,_g,_b));
73 | h = _hsv.x;
74 | l = _hsv.z*(1.0-(_hsv.y*0.5));
75 | s = (_hsv.z-l)/(min(l,1.0-l));
76 | s *= step(-l,-0.000001)*step(l,0.999999);
77 | `,
78 | from: `
79 | _hsv.x = h;
80 | _hsv.z = l + (s*min(l,1.0-l));
81 | _hsv.y = 2.0*(1.0-(l/_hsv.z))*step(-_hsv.z,-0.000001);
82 | vec3 _rgb = _hsvToRgb(_hsv);
83 | _r = _rgb.r; _g = _rgb.g; _b = _rgb.b;
84 | `,
85 | },
86 | {
87 | name: "yuv",
88 | elems: ["y", "u", "v"],
89 | to: `
90 | mat3 rgb2yuv = mat3(0.2126, 0.7152, 0.0722, -0.09991, -0.33609, 0.43600, 0.615, -0.5586, -0.05639);
91 | vec3 _yuv = vec3(_r,_g,_b) * rgb2yuv;
92 | y = _yuv.x; u = _yuv.y; v = _yuv.z;
93 | `,
94 | from: `
95 | mat3 yuv2rgb = mat3(1.0, 0.0, 1.28033, 1.0, -0.21482, -0.38059, 1.0, 2.12798, 0.0);
96 | vec3 _rgb = vec3(y,u,v) * yuv2rgb;
97 | _r = _rgb.r; _g = _rgb.g; _b = _rgb.b;
98 | `,
99 | },
100 | {
101 | name: "yiq",
102 | elems: ["y", "i", "q"],
103 | to: `
104 | mat3 rgb2yiq = mat3(0.299, 0.587, 0.114, 0.5959, -0.2746, -0.3213, 0.2115, -0.5227, 0.3112);
105 | vec3 _yiq = vec3(_r,_g,_b) * rgb2yiq;
106 | y = _yiq.x; i = _yiq.y; q = _yiq.z;
107 | `,
108 | from: `
109 | mat3 yiq2rgb = mat3(1.0, 0.956, 0.619, 1.0, -0.272, -0.647, 1.0, -1.106, 1.703);
110 | vec3 _rgb = vec3(y,i,q) * yiq2rgb;
111 | _r = _rgb.r; _g = _rgb.g; _b = _rgb.b;
112 | `,
113 | },
114 | ];
115 |
116 | // utils
117 |
118 | hcs.generateInputAssignment = function (elems, format) {
119 | return format
120 | ? elems
121 | .map((el) => {
122 | let assign = format;
123 | if (
124 | "yuvalpha,yiqalpha".includes(elems.join("")) &&
125 | "uviq".includes(el) &&
126 | assign.includes("1.0 - #el")
127 | ) {
128 | assign = assign.replaceAll("1.0 - #el", "0.0 - #el");
129 | } // TODO: find a better solution for this patch on inversion
130 | return assign
131 | .replaceAll("#el", el)
132 | .replaceAll("#in", "in_" + el);
133 | })
134 | .join("")
135 | : "";
136 | };
137 |
138 | hcs.generateDirectAssignment = function (elems, tofrom) {
139 | const rgba = ["_r", "_g", "_b", "_a"];
140 | return tofrom == "to"
141 | ? elems.map((el, i) => rgba[i] + " = " + el + ";").join("")
142 | : elems.map((el, i) => el + " = " + rgba[i] + ";").join("");
143 | };
144 |
145 | hcs.generateDeclarations = function (elems, type = "float") {
146 | return elems.map((el) => type + " " + el + ";\n").join("");
147 | };
148 |
149 | // functions that use all elems
150 |
151 | hcs.generateFunction = function ({
152 | colorspace,
153 | sufix,
154 | type,
155 | assignmentFormat,
156 | inputDefault,
157 | alphaDefault = 1,
158 | tofrom,
159 | }) {
160 | const name = colorspace.name + (sufix ? "_" + sufix : "");
161 |
162 | const hasColorInput = ["color", "combine"].includes(type);
163 |
164 | const isRgb = "rgba".includes(colorspace.name);
165 | const elems =
166 | isRgb || tofrom
167 | ? colorspace.elems
168 | : colorspace.elems.concat("alpha");
169 |
170 | const inputs = assignmentFormat
171 | ? elems.map((el) => ({
172 | type: "float",
173 | name: "in_" + el,
174 | default: inputDefault,
175 | }))
176 | : [];
177 | inputs.length ? (inputs.at(-1).default = alphaDefault) : null;
178 |
179 | const rgbaDeclarations = hcs.generateDeclarations([
180 | "_r",
181 | "_g",
182 | "_b",
183 | "_a",
184 | ]);
185 | const rgbaAssignments = hasColorInput
186 | ? "_r = _c0.r; _g = _c0.g; _b = _c0.b; _a = _c0.a;"
187 | : "";
188 |
189 | const elemDeclarations =
190 | hcs.generateDeclarations(elems) +
191 | (isRgb || tofrom ? "" : "alpha = _a;");
192 | const to = hasColorInput || tofrom == "to" ? colorspace.to : "";
193 | const elemAssignments = assignmentFormat
194 | ? hcs.generateInputAssignment(elems, assignmentFormat)
195 | : hcs.generateDirectAssignment(elems, tofrom);
196 | const from = !tofrom || tofrom == "from" ? colorspace.from : "";
197 |
198 | const returner =
199 | (isRgb || tofrom ? "" : "_a = alpha;") +
200 | "return vec4(_r,_g,_b,_a);";
201 |
202 | const glsl =
203 | rgbaDeclarations +
204 | rgbaAssignments +
205 | elemDeclarations +
206 | to +
207 | elemAssignments +
208 | from +
209 | returner;
210 |
211 | return { name: name, type: type, inputs: inputs, glsl: glsl };
212 | };
213 |
214 | hcs.generateColorFunction = (cs) =>
215 | hcs.generateFunction({
216 | colorspace: cs,
217 | sufix: "color",
218 | type: "color",
219 | assignmentFormat: "#el *= #in;",
220 | inputDefault: 1,
221 | alphaDefault: 1,
222 | });
223 | hcs.generateOffsetFunction = (cs) =>
224 | hcs.generateFunction({
225 | colorspace: cs,
226 | sufix: "offset",
227 | type: "color",
228 | assignmentFormat: "#el += #in;",
229 | inputDefault: 0,
230 | alphaDefault: 0,
231 | });
232 | hcs.generateSolidFunction = (cs) =>
233 | hcs.generateFunction({
234 | colorspace: cs,
235 | sufix: "solid",
236 | type: "src",
237 | assignmentFormat: "#el = #in;",
238 | inputDefault: 0,
239 | alphaDefault: 1,
240 | });
241 | hcs.generateToFunction = (cs) =>
242 | hcs.generateFunction({
243 | colorspace: cs,
244 | sufix: "to",
245 | type: "color",
246 | assignmentFormat: undefined,
247 | inputDefault: 0,
248 | alphaDefault: 1,
249 | tofrom: "to",
250 | });
251 | hcs.generateFromFunction = (cs) =>
252 | hcs.generateFunction({
253 | colorspace: cs,
254 | sufix: "from",
255 | type: "color",
256 | assignmentFormat: undefined,
257 | inputDefault: 0,
258 | alphaDefault: 1,
259 | tofrom: "from",
260 | });
261 | hcs.generateInvertFunction = (cs) =>
262 | hcs.generateFunction({
263 | colorspace: cs,
264 | sufix: "invert",
265 | type: "color",
266 | assignmentFormat: "#el = mix(#el, 1.0 - #el, #in);",
267 | inputDefault: 1,
268 | alphaDefault: 0,
269 | });
270 |
271 | // elem functions
272 |
273 | hcs.generateElementFunction = function (colorspace, elem) {
274 | const name = colorspace.name + "_" + elem;
275 |
276 | const type = "color";
277 |
278 | const rgbaDeclarations = hcs.generateDeclarations([
279 | "_r",
280 | "_g",
281 | "_b",
282 | "_a",
283 | ]);
284 | const rgbaAssignments =
285 | "_r = _c0.r; _g = _c0.g; _b = _c0.b; _a = _c0.a;";
286 |
287 | const elemDeclarations = hcs.generateDeclarations(colorspace.elems);
288 | const to = colorspace.to;
289 |
290 | const returner = "return vec4(vec3(" + elem + "),1.0);";
291 |
292 | const glsl =
293 | rgbaDeclarations +
294 | rgbaAssignments +
295 | elemDeclarations +
296 | to +
297 | returner;
298 |
299 | return { name: name, type: type, inputs: [], glsl: glsl };
300 | };
301 |
302 | hcs.generateElementFunctions = (cs) =>
303 | cs.elems.map((elem) => hcs.generateElementFunction(cs, elem));
304 |
305 | hcs.generateSetElementFunction = function ({
306 | colorspace,
307 | elem,
308 | sufix,
309 | assignmentFormat = "#el = #in;",
310 | inputDefault = 1,
311 | }) {
312 | const name = colorspace.name + "_" + elem + "_" + sufix;
313 |
314 | const type = "color";
315 |
316 | const inputs = [
317 | { type: "float", name: "in_" + elem, default: inputDefault },
318 | ];
319 |
320 | const rgbaDeclarations = hcs.generateDeclarations([
321 | "_r",
322 | "_g",
323 | "_b",
324 | "_a",
325 | ]);
326 | const rgbaAssignments =
327 | "_r = _c0.r; _g = _c0.g; _b = _c0.b; _a = _c0.a;";
328 |
329 | const elemDeclarations = hcs.generateDeclarations(colorspace.elems);
330 | const to = colorspace.to;
331 | const elemAssignment = hcs.generateInputAssignment(
332 | [elem],
333 | assignmentFormat
334 | );
335 | const from = colorspace.from;
336 |
337 | const returner = "return vec4(_r,_g,_b,_a);";
338 |
339 | const glsl =
340 | rgbaDeclarations +
341 | rgbaAssignments +
342 | elemDeclarations +
343 | to +
344 | elemAssignment +
345 | from +
346 | returner;
347 |
348 | return { name: name, type: type, inputs: inputs, glsl: glsl };
349 | };
350 |
351 | hcs.generateSetElementFunctions = (cs) =>
352 | cs.elems.map((elem) =>
353 | hcs.generateSetElementFunction({
354 | colorspace: cs,
355 | elem,
356 | sufix: "set",
357 | assignmentFormat: "#el = #in;",
358 | })
359 | );
360 | hcs.generateOffsetElementFunctions = (cs) =>
361 | cs.elems.map((elem) =>
362 | hcs.generateSetElementFunction({
363 | colorspace: cs,
364 | elem,
365 | sufix: "offset",
366 | assignmentFormat: "#el += #in;",
367 | inputDefault: 1,
368 | })
369 | );
370 | hcs.generateMultElementFunctions = (cs) =>
371 | cs.elems.map((elem) =>
372 | hcs.generateSetElementFunction({
373 | colorspace: cs,
374 | elem,
375 | sufix: "mult",
376 | assignmentFormat: "#el *= #in;",
377 | inputDefault: 1,
378 | })
379 | );
380 | hcs.generateInvertElementFunctions = (cs) =>
381 | cs.elems.map((elem) =>
382 | hcs.generateSetElementFunction({
383 | colorspace: cs,
384 | elem,
385 | sufix: "invert",
386 | assignmentFormat: "#el = mix(#el, 1.0 - #el, #in);",
387 | inputDefault: 1,
388 | })
389 | );
390 |
391 | hcs.generateCombineElementFunction = function ({
392 | colorspace,
393 | elem,
394 | sufix,
395 | assignmentFormat = "#el = _c1.r;",
396 | inputDefault = 1,
397 | }) {
398 | const name = colorspace.name + "_" + elem + "_" + sufix;
399 |
400 | const type = "combine";
401 |
402 | const inputs = [{ type: "float", name: "_amt", default: inputDefault }];
403 |
404 | const rgbaDeclarations = hcs.generateDeclarations([
405 | "_r",
406 | "_g",
407 | "_b",
408 | "_a",
409 | ]);
410 | const rgbaAssignments =
411 | "_r = _c0.r; _g = _c0.g; _b = _c0.b; _a = _c0.a;";
412 |
413 | const elemDeclarations = hcs.generateDeclarations(colorspace.elems);
414 | const to = colorspace.to;
415 | const elemAssignment = hcs.generateInputAssignment(
416 | [elem],
417 | assignmentFormat
418 | );
419 | const from = colorspace.from;
420 |
421 | const returner = "return vec4(_r,_g,_b,_a);";
422 |
423 | const glsl =
424 | rgbaDeclarations +
425 | rgbaAssignments +
426 | elemDeclarations +
427 | to +
428 | elemAssignment +
429 | from +
430 | returner;
431 |
432 | return { name: name, type: type, inputs: inputs, glsl: glsl };
433 | };
434 |
435 | hcs.generateSetElementFromFunctions = (cs) =>
436 | cs.elems.map((elem) =>
437 | hcs.generateCombineElementFunction({
438 | colorspace: cs,
439 | elem,
440 | sufix: "from",
441 | assignmentFormat: "#el = mix(#el,_c1.r,_amt);",
442 | inputDefault: 1,
443 | })
444 | );
445 | hcs.generateOffsetElementFromFunctions = (cs) =>
446 | cs.elems.map((elem) =>
447 | hcs.generateCombineElementFunction({
448 | colorspace: cs,
449 | elem,
450 | sufix: "offset_from",
451 | assignmentFormat: "#el += _c1.r*_amt;",
452 | inputDefault: 1,
453 | })
454 | );
455 | hcs.generateMultElementFromFunctions = (cs) =>
456 | cs.elems.map((elem) =>
457 | hcs.generateCombineElementFunction({
458 | colorspace: cs,
459 | elem,
460 | sufix: "mult_from",
461 | assignmentFormat: "#el *= _c1.r*_amt;",
462 | inputDefault: 1,
463 | })
464 | );
465 |
466 | // keying
467 |
468 | hcs.generateKeyingElementFunction = function ({ colorspace, elem }) {
469 | const name = colorspace.name + "_" + elem + "_" + "key";
470 |
471 | const type = "color";
472 |
473 | const inputs = [
474 | { type: "float", name: "_th0", default: 0.5 },
475 | { type: "float", name: "_t0", default: 0.05 },
476 | { type: "float", name: "_th1", default: 0 },
477 | { type: "float", name: "_t1", default: 0 },
478 | ];
479 |
480 | const isRgb = "rgba".includes(colorspace.name);
481 | const rgbaDeclarations = hcs.generateDeclarations([
482 | "_r",
483 | "_g",
484 | "_b",
485 | "_a",
486 | ]);
487 | const rgbaAssignments =
488 | "_r = _c0.r; _g = _c0.g; _b = _c0.b; _a = _c0.a;";
489 |
490 | const elemDeclarations = hcs.generateDeclarations(colorspace.elems);
491 | const to = colorspace.to;
492 | const keying = (
493 | "float _key = smoothstep(_th0-(_t0+0.0000001), _th0+(_t0+0.0000001), #elem);" +
494 | "_th1 = 1.0 - _th1 + 0.0000001; _key *= smoothstep(_th1-(-_t1-0.0000001), _th1+(-_t1-0.0000001), #elem);" +
495 | (isRgb ? "a" : "_a") +
496 | " *= _key;"
497 | ).replaceAll("#elem", elem);
498 | const from = colorspace.from;
499 |
500 | const returner = "return vec4(_r,_g,_b,_a);";
501 |
502 | const glsl =
503 | rgbaDeclarations +
504 | rgbaAssignments +
505 | elemDeclarations +
506 | to +
507 | keying +
508 | from +
509 | returner;
510 |
511 | return { name: name, type: type, inputs: inputs, glsl: glsl };
512 | };
513 |
514 | hcs.generateKeyingElementFunctions = (cs) =>
515 | cs.elems.map((elem) =>
516 | hcs.generateKeyingElementFunction({
517 | colorspace: cs,
518 | elem,
519 | })
520 | );
521 |
522 | // updaters
523 |
524 | hcs.updateFunctions = function () {
525 | []
526 | .concat(
527 | hcs.colorspaces.map(hcs.generateColorFunction),
528 | hcs.colorspaces.map(hcs.generateOffsetFunction),
529 | hcs.colorspaces.map(hcs.generateSolidFunction),
530 | hcs.colorspaces.map(hcs.generateToFunction),
531 | hcs.colorspaces.map(hcs.generateFromFunction),
532 | hcs.colorspaces.map(hcs.generateInvertFunction),
533 | hcs.colorspaces.map(hcs.generateElementFunctions),
534 | hcs.colorspaces.map(hcs.generateSetElementFunctions),
535 | hcs.colorspaces.map(hcs.generateOffsetElementFunctions),
536 | hcs.colorspaces.map(hcs.generateMultElementFunctions),
537 | hcs.colorspaces.map(hcs.generateInvertElementFunctions),
538 | hcs.colorspaces.map(hcs.generateSetElementFromFunctions),
539 | hcs.colorspaces.map(hcs.generateOffsetElementFromFunctions),
540 | hcs.colorspaces.map(hcs.generateMultElementFromFunctions),
541 | hcs.colorspaces.map(hcs.generateKeyingElementFunctions)
542 | )
543 | .flat(99)
544 | .filter((x) => x)
545 | .forEach((x) => _hydra.synth.setFunction(x));
546 | };
547 |
548 | hcs.cloneGlslSource = function (_tex) {
549 | const tex = Object.assign({}, _tex);
550 | Object.setPrototypeOf(tex, gS);
551 | tex.transforms = Array.from(_tex.transforms);
552 | return tex;
553 | };
554 |
555 | hcs.updateWithFunctions = function () {
556 | hcs.colorspaces.forEach((cs) => {
557 | cs.elems.forEach((el) => {
558 | gS[cs.name + "_" + el + "_" + "with"] = function (f) {
559 | const tex = hcs.cloneGlslSource(this);
560 | return this[cs.name + "_" + el + "_" + "from"](
561 | f(tex)[cs.name + "_" + el]()
562 | );
563 | };
564 | });
565 | });
566 | };
567 |
568 | hcs.update = function () {
569 | hcs.updateFunctions();
570 | hcs.updateWithFunctions();
571 | hcs.colorspaces.forEach((cs) => {
572 | let getterDefinition =
573 | "Object.defineProperty(gS, '#cs', { configurable: true, get: function() {" +
574 | "const func = this.#cs_color.bind(this);";
575 | getterDefinition +=
576 | "const props = {" +
577 | "color: this.#cs_color.bind(this)," +
578 | "offset: this.#cs_offset.bind(this)," +
579 | "to: this.#cs_to.bind(this)," +
580 | "from: this.#cs_from.bind(this)," +
581 | "invert: this.#cs_invert.bind(this),";
582 | cs.elems.forEach((elem) => {
583 | getterDefinition +=
584 | "#elem: this.#cs_#elem.bind(this)," +
585 | "#elemSet: this.#cs_#elem_set.bind(this)," +
586 | "#elemOffset: this.#cs_#elem_offset.bind(this)," +
587 | "#elemMult: this.#cs_#elem_mult.bind(this)," +
588 | "#elemInvert: this.#cs_#elem_invert.bind(this)," +
589 | "#elemFrom: this.#cs_#elem_from.bind(this)," +
590 | "#elemOffsetFrom: this.#cs_#elem_offset_from.bind(this)," +
591 | "#elemMultFrom: this.#cs_#elem_mult_from.bind(this)," +
592 | "#elemKey: this.#cs_#elem_key.bind(this)," +
593 | "#elemWith: this.#cs_#elem_with.bind(this),";
594 | getterDefinition = getterDefinition.replaceAll("#elem", elem);
595 | });
596 | getterDefinition += "};";
597 | getterDefinition +=
598 | "Object.assign(func,props);" + "return func; }, });";
599 | getterDefinition += "_hydraScope.#cs = _hydraScope.#cs_solid;";
600 | getterDefinition = getterDefinition.replaceAll("#cs", cs.name);
601 | window.eval(getterDefinition);
602 | });
603 | };
604 |
605 | hcs.update();
606 |
607 | window.hydraColorspaces = {};
608 | hydraColorspaces.colorspaces = hcs.colorspaces;
609 | hydraColorspaces.update = hcs.update.bind(hcs);
610 | }
611 |
--------------------------------------------------------------------------------