CSS Gradient Generator — JavaScript source
Build linear, radial, and conic CSS gradients with multiple color stops and positions. Live preview and copy-ready CSS.
This is the JavaScript implementation — the same logic the interactive tool runs, in a shareable, citable form.
/**
* Pure CSS-gradient builder - JavaScript polyglot showcase port.
*
* Language: JavaScript (ES module, no dependencies, no DOM)
* Origin: CosmoDev polyglot showcase - port of the css-gradient-generator tool
* Ported from: src/lib/cssGradient.ts (the canonical TypeScript implementation)
*
* Purpose: Build linear / radial / conic CSS gradient strings from a small
* config object. Deterministic and side-effect free - never throws.
*
* Display source - part of CosmoDev's polyglot tool pages.
*/
/**
* Named CSS colors this tool accepts. The full CSS spec defines ~148 names,
* but we accept only the common, unambiguous set so output stays predictable.
*/
const NAMED_COLORS = new Set([
'transparent', 'black', 'white', 'red', 'green', 'blue', 'yellow',
'orange', 'purple', 'pink', 'gray', 'grey', 'brown', 'cyan', 'magenta',
'none', 'currentcolor',
]);
// Regexes mirror the TypeScript source exactly: 3- or 6-digit hex, 8-digit
// alpha hex, and the rgb()/rgba() / hsl()/hsla() functional forms.
const HEX_3_OR_6 = /^#[0-9a-f]{3}([0-9a-f]{3})?$/;
const HEX_8 = /^#[0-9a-f]{8}$/;
const RGB_FUNC = /^rgba?\([^)]+\)$/;
const HSL_FUNC = /^hsla?\([^)]+\)$/;
/**
* Validate a CSS color string.
* Returns { ok, error } - error is null when ok, a human message otherwise.
*/
export function parseColor(color) {
const c = (color || '').trim().toLowerCase();
if (!c) return { ok: false, error: 'empty color' };
if (NAMED_COLORS.has(c)) return { ok: true, error: null };
if (HEX_3_OR_6.test(c)) return { ok: true, error: null };
if (HEX_8.test(c)) return { ok: true, error: null };
if (RGB_FUNC.test(c)) return { ok: true, error: null };
if (HSL_FUNC.test(c)) return { ok: true, error: null };
return { ok: false, error: `invalid color: ${color}` };
}
/**
* Coerce a possibly-invalid color to a safe value. Invalid colors become solid
* black so the gradient always renders. The original casing is preserved - we
* only ever trim, mirroring the TypeScript source.
*/
function normalizeColor(color) {
const { ok } = parseColor(color);
return ok ? color.trim() : '#000000';
}
/**
* Build a complete CSS gradient string from a config:
* { type: 'linear'|'radial'|'conic', angle, stops: [{color, position}], radialShape? }
*
* Stops are sorted ascending by position. Fewer than 2 stops collapse to a
* safe black → white default so the output is always renderable. Positions are
* rounded to integers via Math.round (half rounds toward +∞). `radialShape`
* uses nullish coalescing: only null/undefined falls back to "circle"; an
* explicit empty string passes through.
*/
export function buildGradient(config) {
let stops = [...config.stops].sort((a, b) => a.position - b.position);
// Drop nonsensical entries; pad if fewer than 2.
if (stops.length < 2) {
stops = [
{ color: '#000000', position: 0 },
{ color: '#ffffff', position: 100 },
];
}
const stopsStr = stops
.map((s) => `${normalizeColor(s.color)} ${Math.round(s.position)}%`)
.join(', ');
switch (config.type) {
case 'linear':
return `linear-gradient(${config.angle}deg, ${stopsStr})`;
case 'radial':
return `radial-gradient(${config.radialShape ?? 'circle'}, ${stopsStr})`;
case 'conic':
return `conic-gradient(from ${config.angle}deg, ${stopsStr})`;
}
// Unhandled type - mirrors the TypeScript, which falls off the switch and
// implicitly returns undefined.
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →