Initial commit.
This commit is contained in:
commit
977917475f
3
.babelrc
Normal file
3
.babelrc
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["latest"]
|
||||
}
|
10
.editorconfig
Normal file
10
.editorconfig
Normal file
@ -0,0 +1,10 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
lib
|
25
package.json
Normal file
25
package.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "themer-wallpaper-block-wave",
|
||||
"version": "1.0.0",
|
||||
"description": "Wallpaper generator for themer.",
|
||||
"main": "lib/index.js",
|
||||
"author": "mjswensen",
|
||||
"license": "MIT",
|
||||
"jest": {
|
||||
"rootDir": "lib"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "babel --out-dir lib src",
|
||||
"start": "watch 'yarn run build' src",
|
||||
"test": "jest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.18.0",
|
||||
"babel-preset-latest": "^6.16.0",
|
||||
"jest-cli": "^17.0.3",
|
||||
"watch": "^1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"svg2png": "^4.1.0"
|
||||
}
|
||||
}
|
90
src/index.js
Normal file
90
src/index.js
Normal file
@ -0,0 +1,90 @@
|
||||
import weightedRandom from './weighted-random';
|
||||
import svg2png from 'svg2png';
|
||||
|
||||
export const render = (colors, options) => {
|
||||
|
||||
const colorWeights = new Map([
|
||||
['accent0', 1],
|
||||
['accent1', 1],
|
||||
['accent2', 1],
|
||||
['accent3', 1],
|
||||
['accent4', 1],
|
||||
['accent5', 1],
|
||||
['accent6', 1],
|
||||
['accent7', 1],
|
||||
['shade0', 0],
|
||||
['shade1', 8],
|
||||
['shade2', 6],
|
||||
['shade3', 4],
|
||||
['shade4', 3],
|
||||
['shade5', 2],
|
||||
['shade6', 1],
|
||||
['shade7', 1],
|
||||
]);
|
||||
|
||||
const colorSets = [{ name: 'dark', colors: colors.dark }, { name: 'light', colors: colors.light }].filter(colorSet => !!colorSet.colors);
|
||||
|
||||
const sizes = [ // TODO: get from args with this and a device being the default
|
||||
{
|
||||
w: 2880,
|
||||
h: 1800,
|
||||
s: 36,
|
||||
},
|
||||
];
|
||||
|
||||
const deepFlatten = arr => arr.reduce((cumulative, inner) => cumulative.concat(Array.isArray(inner) ? deepFlatten(inner) : inner), []);
|
||||
|
||||
return deepFlatten(colorSets.map(colorSet => sizes.map(size => {
|
||||
let blockMaxSize = size.s / 3;
|
||||
let blockMinSize = blockMaxSize * 2/3;
|
||||
let blocks = [];
|
||||
for (let i = 0; i < size.w; i += size.s) {
|
||||
for (let j = 0; j < size.h; j += size.s) {
|
||||
let color = colorSet.colors[weightedRandom(colorWeights)];
|
||||
let xPosition = (i + size.s / 2) / size.w;
|
||||
let yPosition = (j + size.s / 2) / size.h;
|
||||
let positionScaleFactor = Math.abs(xPosition - yPosition);
|
||||
let blockSize = blockMaxSize - (blockMaxSize - blockMinSize) * positionScaleFactor;
|
||||
let padding = (size.s - blockSize) / 2;
|
||||
blocks.push({
|
||||
x: i + padding,
|
||||
y: j + padding,
|
||||
w: blockSize,
|
||||
h: blockSize,
|
||||
c: color,
|
||||
g: Math.random() < 0.01,
|
||||
});
|
||||
}
|
||||
}
|
||||
return { size: size, blocks: blocks };
|
||||
}).map(svgData => {
|
||||
const svgString = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" style="background-color: ${colorSet.colors.shade0};" width="${svgData.size.w}" height="${svgData.size.h}" viewBox="0 0 ${svgData.size.w} ${svgData.size.h}">
|
||||
<defs>
|
||||
<linearGradient id="overlay" x1="1" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="${colorSet.colors.shade0}"/>
|
||||
<stop offset="50%" stop-color="${colorSet.colors.shade0}" stop-opacity="0"/>
|
||||
<stop offset="100%" stop-color="${colorSet.colors.shade0}"/>
|
||||
</linearGradient>
|
||||
<filter id="glow">
|
||||
<feGaussianBlur stdDeviation="5" result="coloredBlur"/>
|
||||
<feMerge>
|
||||
<feMergeNode in="coloredBlur"/>
|
||||
<feMergeNode in="SourceGraphic"/>
|
||||
</feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
${svgData.blocks.map(block => `<rect x="${block.x}" y="${block.y}" width="${block.w}" height="${block.h}" fill="${block.c}" rx="2" ry="2" ${block.g ? `filter="url(#glow)"` : ''} />`).join('\n')}
|
||||
<rect x="0" y="0" width="${svgData.size.w}" height="${svgData.size.h}" fill="url(#overlay)"/>
|
||||
</svg>
|
||||
`;
|
||||
const basename = `themer-wallpaper-block-wave-${colorSet.name}-${svgData.size.w}x${svgData.size.h}`;
|
||||
const svgBuffer = new Buffer(svgString, 'utf-8');
|
||||
return [
|
||||
Promise.resolve({ name: `${basename}.svg`, contents: svgBuffer }),
|
||||
svg2png(svgBuffer).then(pngBuffer => ({ name: `${basename}.png`, contents: pngBuffer })),
|
||||
];
|
||||
})
|
||||
));
|
||||
|
||||
};
|
5
src/weighted-random.js
Normal file
5
src/weighted-random.js
Normal file
@ -0,0 +1,5 @@
|
||||
export default map => {
|
||||
const cumulativeWeights = Array.from(map.values()).reduce((c, weight, i) => c.concat(weight + (i === 0 ? 0 : c[i-1])), []);
|
||||
const random = cumulativeWeights[cumulativeWeights.length-1] * Math.random();
|
||||
return Array.from(map.keys())[cumulativeWeights.findIndex(cw => random < cw)];
|
||||
};
|
27
src/weighted-random.test.js
Normal file
27
src/weighted-random.test.js
Normal file
@ -0,0 +1,27 @@
|
||||
import wr from './weighted-random';
|
||||
|
||||
describe('weighted random', () => {
|
||||
it('selects a random key from a map of keys to weights', () => {
|
||||
|
||||
const testData = new Map([
|
||||
['a', 1],
|
||||
['b', 3],
|
||||
['c', 1],
|
||||
]);
|
||||
const total = Array.from(testData.values()).reduce((total, weight) => total + weight, 0);
|
||||
const samples = 1000;
|
||||
|
||||
let frequency = {
|
||||
'a': 0,
|
||||
'b': 0,
|
||||
'c': 0,
|
||||
};
|
||||
|
||||
for (let i = 0; i < total * samples; i++) frequency[wr(testData)]++;
|
||||
|
||||
expect(Math.round(frequency['a'] / samples)).toBe(1);
|
||||
expect(Math.round(frequency['b'] / samples)).toBe(3);
|
||||
expect(Math.round(frequency['c'] / samples)).toBe(1);
|
||||
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user