Complement Node

john's Avatar


03 May, 2024 12:09 AM

Another new color node: complement!

The complement node creates complementary colors based on a supplied color. It takes the following arguments:

  • Color. The base color
  • Total Colors. The total number of colors you want (including the base color)
  • Wheel. The color wheel or mode used to form the complements. There are four options:
    • Standard - RGB: The classic Red Green Blue color wheel
    • Painter - RYB: A traditional Red Yellow Blue wheel often favored by artists
    • Perceptual - HCL: A perceptually smooth wheel based on an HCL (Hue Chroma Lightness) color model
    • Monochromatic: Generate colors by varying the saturation, brightness, and/or alpha of the base color's hue
  • Saturation Range. The maximum change in saturation from -100% to +100%. Only applies to Monochromatic mode.
  • Brightness Range. The maximum change in brightness from -100% to +100%. Only applies to Monochromatic mode.
  • Alpha Range. The maximum change in transparency from -100% to +100%. Only applies to Monochromatic mode.

The attached demo (see screenshot) shows three possible uses of this node.

  • The blue sky background is a gradient formed by generating 100 monochromatic shades of a blue base, by varying saturation and brightness.
  • The fuzzy sun is created with another monochromatic gradient, this time varying the alpha value as well.
  • The 12-value color wheel is generated with 12 colors complementary to a base red. You can easily generate a standard (equilateral) triadic palette by changing that 12 to a 3. If you instead want to make a "split complementary" palette based on an isosceles triangle, one way of doing this is to generate 12 colors and then use only the first, fifth, and seventh of these.

You can get a good feel of how this all works by adjusting the settings of the three complement nodes controlling the sky, sun, and wheel diagram. Monochromatic complements are great for creating subtle gradients. You can immediately understand the three wheel-based complements by adjusting the base color and trying each of the three wheels.

The demo also includes two other simple networks:

  • The network on the lower right creates color wheels using my donut node. Color wheels are now very easy to make using the complement node.
  • Then network on the upper right shows the hue relationship between the normal RYB hues (controlled by a standard HSB node) and hue values generated from an RYB wheel. Calculating hue values from an RYB wheel is tricky; RYB is not a true color model but rather a rearrangement of standard RGB primaries with underlying subtractive (rather than additive) color mixing, so I could not locate any formulas to do this on the web. To determine a hue value I was forced to recreate an RYB wheel and find the angle at which that hue occurs. To make this easier in the future, I created an RYB_hue node that returns the RYB hue as a value from 0 to 1 (as a standard hue lookup also does). The network plots a curve showing the relationship between the RYB hues (in light red) against RGB hues (the X axis). The initially rising red curve shows how the spectrum from red to yellow is stretched on the RYB wheel, while other parts of the spectrum are compressed. I don't expect anyone but me will ever use the RYB_hue node, but adventurous color theorists may find it useful someday.

The complement node provides another way of generating a palette of colors. It joins my toolbox of similar color nodes:

  • color_brewer
  • colors
  • luma_colors
  • palette

Each of these nodes attacks the challenge of generating color lists from a different angle: preset balanced palettes, random colors between fixed endpoints, colors with a similar luma value, palettes extended from a base palette, and now colors complementary to a base color. You can then use my other color nodes to further tweak these oolors.

Complement will be included in the next release of my node library and is, as always, free to use with no restrictions. Happy coloring!

  1. 1 Posted by crowinvader on 19 Jun, 2024 06:36 AM

    crowinvader's Avatar

    Hi John, Ive been lurking on here for about a month and I have been learning a lot of stuff from all your helpful posts! than you so much!

    I have some shapes aligned to a grid, if I use this complement node it seems to create copies of all the polygons, I cant seem to isolate why it might be happening.

    Essentially I have recreated this but I want to have each side of the cubes to have different colors, but each individual cube to have unique colors also. I managed to get towards the effect Im after by using an multiply with the random number into the color node, but that resulted in a uniform rainbow like spectrum change, not quite fully random. Can you point me in the right direction?

  2. Support Staff 2 Posted by john on 19 Jun, 2024 09:35 AM

    john's Avatar

    Hi Crowinvader,

    It's hard for me to guess exactly what your problem is without seeing your code. I don't know if you are using subnetworks (e.g. a cube node) and, if so, if you have placed your color nodes inside that subnetwork or are passing colors as a list.

    There are many ways to draw complex shapes aligned to a grid, many ways to color them, and many things that can go wrong.

    Usually, though, this kind of problem arises when you are passing multiple lists into a node (like a list of positions and a list of colors).

    Generally speaking, a node will fire once each time it receives a value. Things get more complicated when a node receives multiple lists of values. Usually the longer list will determine how many times the node fires and the shorter list will keep repeating as needed.

    So if you have a subnetwork called cube which draws a group of three isometric faces at a certain position, and if you feed it a list of 10 positions from a grid, the node will fire 10 times and draw 10 cubes, one at each position.

    But if you then add a color port to your cube node, and try to pass it a list of 30 colors (3 for each cube), that cube node will fire 30 times, not 10. It will fire once for each color it receives (not once for every 3 colors), and the positions will repeat, so the 30 cubes will be drawn on top of each other, 3 at each position. This can be quite confusing since you may not even notice that each cube is actually 3 superimposed cubes.

    That's just one example. Instead of passing 30 colors to a single color port, you could make 3 ports (front color, side color, top color) and feed 10 colors into each of those 3 ports (along with the 10 positions from the grid). That could work, but it will be a little tricky coordinating the 3 color lists.

    Alternatively, you could pass just the front color to each cube and put my complements node inside the cube subnetwork. That way, you can pass 10 colors to go with the 10 positions, the node will fire 10 times, and the other two faces can be colored inside the cube node.

    I have created a demo showing how this last method can work (see attached screenshot and demo). I create a "bar" subnetwork that draws an isometric bar consisting of three faces grouped together as a single unit at a given position. I feed it 27 positions (3 rows of 9 columns each) to draw 27 bars.

    I then feed the list of bars into a "colorize_bar" subnetwork which also takes a list of front colors and settings for my complements node (which is inside the colorize_bar node). I feed it 27 random colors from my colors node. Colorize_bar uses my complements node to derive side and top colors from each front color, then ungroups the bar, colors it with those 3 colors, and regroups it. Mission accomplished.

    This demo is quite a bit of fun. Changing any setting on any node will cause something interesting to happen. I used a monochromatic color wheel; change that to see more varied and colorful bars. Fiddle with the colors node or replace it with some other method of generating front colors. Just for fun I varied the height of the bars using a wave node; see what happens when you change the size of the grid or the period of the sign wave.

    And, of course, you can peer inside the subnetworks to see how they work.

    Coloring 3 elements of each item in list of objects is a tricky thing to do. You pretty much have to use subnetworks to pull this off. In fact, the main purpose of subnetworks is to handle the choreography of complex interactions like this.

    In order to keep it all straight, you have to be very clear about what you are feeding into your subnetwork, how many items are in each incoming list, how often your subnetwork is firing, and exactly what it's going to do each time it fires. If you make a cube subnetwork you should think about whether each cube it spits out is a single object (a group), or is in fact a list of separate faces. Either way can work, but you have to be very clear about what you're doing.

    You should get in the habit of constantly switching between viewer and data view to see if those 10 cubes you see on the screen are really 10 cubes (10 geometries), or 30 faces (30 paths), or even 30 geometries stacked on top of each other. If you are assuming each list feeding into your cube node has the same number of items, you should doublecheck to verify this is actually the case.

    I hope I haven't overwhelmed you. This kind of choreography is tricky but goes to the heart of how Nodebox works. It takes some getting used to, but once you do get used to it, you can quickly and elegantly do many amazing things.

    Please play with my demo. If you are still confused, reply and include a zipped copy of your NDBX file.

    And thanks for reaching out for help. I hope to hear from you again!


  3. 3 Posted by crowinvader on 20 Jun, 2024 06:30 AM

    crowinvader's Avatar

    Hi John, thanks so much, above and beyond as usual. Ive spent some time looking at your example and mine and of course you are right, the geo on my version was hiding behind the front most polygon, I had an inkling, because you could sometimes glimpse a different color towards the edges when you adjust some things. I will remember to check the data button in future.

    I need some time to properly have a look at your example, but I can already see the switches for randomizing the color get you a lot further than what I had. I guess randomizing the color will still be a linear spectrum applied to the array unless you do this?

    I will post when I have something less of an embarrassing mess, in the meantime let me share with you my inspiration and the Korean artist that got me interested in nodebox, She has a great eye for design and color and seems to work mostly in nodebox.

  4. Support Staff 4 Posted by john on 20 Jun, 2024 09:55 AM

    john's Avatar


    Glad I was able to help.

    Most of my color palette nodes ultimately do move across spectrums of color in a linear way, but this will only be apparent with larger palettes, and if you don't want that effect you can use the randomize and/or shuffle options. OR you can handcraft a basic (non-linear) palette then extend it using my palette node. OR you can roll your own palettes in an infinite number of ways. You can hook a wave node or my easing nodes into an HSB node to generate waves or rising tides of color. You can even sample colors from images if you want using my image node. The main problem with colors is making a choice given all the endless possibilities.

    I was pleased that you mentioned Seohyo. She's an old friend of mine (though we've never actually met). Her work is now seen in many public venues, on the sides of buildings around the world and in the Incheon Airport. She does indeed work almost exclusively in Nodebox. She teaches Nodebox to her students, uses some of the nodes from my library in her work, and was the one who first encouraged me to sell my Nodebox animations as NFTs. She was also kind enough to fly to Japan (twice) to film public exhibitions where both of our work was featured. She is certainly one of the leading Nodebox artists in the world and is a wonderful person.

    Were you one of her students?

  5. 5 Posted by crowinvader on 21 Jun, 2024 06:53 AM

    crowinvader's Avatar

    I have tried the wave using the frame rate to animate color and scale, but most recently Ive been using the simplex noise from one of the threads for the movement. Actually I was going to ask you how I might add different types of noise?

    Not a student, just a fan. Do you have a gallery online somewhere? I would love to see some more of your nodebox work!

  6. Support Staff 6 Posted by john on 27 Jun, 2024 01:57 PM

    john's Avatar

    Hi Crowinvader,

    My apologies! The forum software dumped your last message in the spam folder for some reason and I only just now saw it.

    "Add different types of noise" could have many meanings. You could add specks and dust and scratches to colored shapes, or you could disrupt orderly arrangements (e.g. by wiggling points in a grid or add jittering to a data plot), or you could add noise to movements or gradients by using random walks instead of linear progressions or you could add noise to a color palette by introducing slight variations of color.

    For all of these meanings there are many different ways of "adding noise". Could you say a little more precisely exactly what you mean by adding noise? Also, which "simplex noise" node are you using?

    I do keep a portfolio of my NodeBox art at Instagram:

    More links here:

    Again, my apologies for the delay in responding. Hope you are still there!

Reply to this discussion

Internal reply

Formatting help / Preview (switch to plain text) No formatting (switch to Markdown)

Attaching KB article:


Already uploaded files

  • complement_node_screenshot.png 757 KB
  • 333 KB

Attached Files

You can attach files up to 10MB

If you don't have an account yet, we need to confirm you're human and not a machine trying to post spam.

Keyboard shortcuts


? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac

Recent Discussions

23 Jul, 2024 04:46 PM
22 Jul, 2024 07:50 AM
11 Jul, 2024 03:48 PM
28 Jun, 2024 01:51 PM
27 Jun, 2024 02:56 PM


27 Jun, 2024 01:57 PM
26 Jun, 2024 08:17 PM
26 Jun, 2024 11:35 AM
24 Jun, 2024 02:42 AM
24 Jun, 2024 12:46 AM
23 Jun, 2024 08:07 AM