themer
Version:
Customizable theme creator for editors, terminals, wallpaper, and more.
178 lines • 7.05 kB
JavaScript
import { listOutputFiles, weightedRandom } from './index.js';
import { colorSetToVariants } from '../color-set/index.js';
import { source } from 'common-tags';
const BORDER_SIZE = 75;
const GRID_CELL_SIZE = 30;
const END_CAP_SIZE = 5;
const FIND_PATH_TRY_COUNT = 4;
const JITTER = 0.5;
class Point {
x;
y;
static add(a, b) {
return new Point(a.x + b.x, a.y + b.y);
}
static subtract(a, b) {
return new Point(a.x - b.x, a.y - b.y);
}
clone() {
return new Point(this.x, this.y);
}
constructor(x, y) {
this.x = x;
this.y = y;
}
}
const template = {
name: 'Circuits wallpaper',
render: async function* (colorSet, options) {
const variants = colorSetToVariants(colorSet);
for (const variant of variants) {
for (const size of options.wallpaperSizes) {
// Calculate the drawing area
const columnCount = Math.floor((size.w - BORDER_SIZE * 2) / GRID_CELL_SIZE);
const rowCount = Math.floor((size.h - BORDER_SIZE * 2) / GRID_CELL_SIZE);
const gridWidth = columnCount * GRID_CELL_SIZE;
const gridHeight = rowCount * GRID_CELL_SIZE;
const gridOriginX = (size.w - gridWidth) / 2;
const gridOriginY = (size.h - gridHeight) / 2;
const gridCellState = new Map();
for (let i = 0; i < columnCount; i++) {
const column = new Map();
for (let j = 0; j < rowCount; j++) {
column.set(j, null);
}
gridCellState.set(i, column);
}
function getNext(start, previous) {
const options = [
new Point(0, -1),
new Point(1, 0),
new Point(0, 1),
new Point(-1, 0),
].filter((option) => previous
? !(option.x === previous.x && option.y === previous.y)
: true);
for (let tryCount = 0; tryCount < FIND_PATH_TRY_COUNT; tryCount++) {
const proposed = Point.add(start, options[Math.floor(Math.random() * options.length)]);
if (gridCellState.has(proposed.x) &&
gridCellState.get(proposed.x).has(proposed.y) &&
gridCellState.get(proposed.x).get(proposed.y) === null) {
return proposed;
}
}
return null;
}
function jitter() {
return (Math.random() - 0.5) * END_CAP_SIZE * JITTER;
}
function getCenter(point) {
return new Point(gridOriginX +
point.x * GRID_CELL_SIZE +
GRID_CELL_SIZE / 2 +
jitter(), gridOriginY +
point.y * GRID_CELL_SIZE +
GRID_CELL_SIZE / 2 +
jitter());
}
const paths = [];
for (const [x, column] of gridCellState.entries()) {
for (const [y, cell] of column.entries()) {
if (cell === null) {
let previous = null;
let current = new Point(x, y);
const points = [current.clone()];
gridCellState.get(current.x).set(current.y, true);
let next;
while ((next = getNext(current, previous && Point.subtract(previous, current))) !== null) {
points.push(next.clone());
gridCellState.get(next.x).set(next.y, true);
previous = current;
current = next;
}
paths.push(points);
}
}
}
function getStrokeStyle() {
return weightedRandom(new Map([
[variant.colors.shade2, 50],
[variant.colors.accent0, 1],
[variant.colors.accent1, 1],
[variant.colors.accent2, 1],
[variant.colors.accent3, 1],
[variant.colors.accent4, 1],
[variant.colors.accent5, 1],
[variant.colors.accent6, 1],
[variant.colors.accent7, 1],
]));
}
const elements = [];
paths.forEach((points) => {
const strokeColor = points.length > 1 ? getStrokeStyle() : variant.colors.shade1;
elements.push(source `
<path
fill="none"
stroke="${strokeColor}"
stroke-width="2.5"
d="${points
.map((point, i) => {
const c = getCenter(point);
return i === 0 ? `M${c.x},${c.y}` : `L${c.x},${c.y}`;
})
.join(' ')}"
/>
`);
const startCenter = getCenter(points[0]);
elements.push(source `
<circle
cx="${startCenter.x}"
cy="${startCenter.y}"
r="${END_CAP_SIZE}"
fill="${variant.colors.shade0}"
stroke="${strokeColor}"
stroke-width="2.5"
/>
`);
if (points.length > 1) {
const endCenter = getCenter(points[points.length - 1]);
elements.push(source `
<circle
cx="${endCenter.x}"
cy="${endCenter.y}"
r="${END_CAP_SIZE}"
fill="${variant.colors.shade0}"
stroke="${strokeColor}"
stroke-width="2.5"
/>
`);
}
});
const svg = source `
<svg
xmlns="http://www.w3.org/2000/svg"
width="${size.w}"
height="${size.h}"
viewBox="0 0 ${size.w} ${size.h}"
>
<rect
x="0"
y="0"
width="${size.w}"
height="${size.h}"
fill="${variant.colors.shade0}"
/>
${elements}
</svg>
`;
yield {
path: `${variant.title.kebab}-${size.w}x${size.h}.svg`,
content: svg,
};
}
}
},
renderInstructions: listOutputFiles,
};
export default template;
//# sourceMappingURL=wallpaper-circuits.js.map