Type or paste channel values and get the hex, HSL and CSS forms, plus what those channels score against black and white. The arithmetic runs on your own machine, so no value you type is uploaded.
These are the values for the last colour that parsed. The message above says what is wrong with the one in the field.
#663399
2.50 to 1
Black text on this colour
AA ✗AAA ✗AA large ✗
8.41 to 1
White text on this colour
AA ✓AAA ✓AA large ✓
White text is the stronger pairing on this colour.
rgb(102, 51, 153) and #663399 are the same colour. The difference is that one of them is a value you can do arithmetic on. You want the numbers whenever a colour is an input rather than a label — and when the colour arrived as a hex string from a design file in the first place, HEX to RGB is this same converter pointed the other way, with the case for why the handover takes that form.
fillStyle takes a string, but pixel work does not: ImageData is a flat array of channel bytes, and anything that tints, blends or samples operates on those.This is why a lot of design systems store colours as bare channels rather than as hex. Set --brand: 102 51 153, then write background: rgb(var(--brand)) for the solid colour and background: rgb(var(--brand) / 12%) for a tint of it. One token serves the colour and every transparency built from it.
The version people try first does not work: if --brand holds rgb(102, 51, 153), then rgba(var(--brand), .12) expands to rgba(rgb(102, 51, 153), .12), which is invalid and silently drops the declaration. Store the three numbers, not the function call. The RGB row above gives them to you with commas — delete those for the custom property form.
Modern CSS takes rgb(102 51 153 / 40%), with spaces between channels and a slash before alpha. rgba() is now simply an alias for rgb(), kept for compatibility, and current browsers accept either separator style in either function. Percentages work as well, and values outside 0 to 255 are clamped rather than rejected, which is why 300 becomes 255 here too instead of throwing an error at you.
Round-tripping through HSL is lossy. hsl() lands on integer degrees and percentages, so #2F80ED converted to HSL and back comes out as #3182ED. Visually identical, not byte identical, and a diff or a visual regression test will flag it. Convert once from the source value rather than through a chain of formats.
Averaging channels gives muddy midpoints. A blue-to-yellow gradient interpolated in sRGB passes through grey, because the two colours cancel channel by channel. When the midpoint matters, let CSS mix somewhere better — color-mix(in oklab, …), or a gradient declared in oklch — and keep straight channel maths for the jobs that are genuinely arithmetic.
SVG to PNG
Convert SVG files to PNG at any scale, in the browser. Batch and transparent background.
HEX to RGB
Paste a hex colour, get RGB, HSL and CSS you can copy.
PNG to SVG
Trace a bitmap into vector paths, in the browser. Honest about when it works.
CSS Grid generator
Draw a grid, copy the CSS. Flexbox on a second tab.
Mesh gradient generator
Layered radial gradients, exportable as CSS or PNG.
OG image generator
Make a 1200x630 share card, and check the tags on a page you already have.
Website mockup generator
Drop a screenshot into a browser or device frame and export it.
Designing a site? Siter.io builds it from Figma.