Initial commit.

This commit is contained in:
Matt Swensen 2016-11-23 06:50:03 -07:00
commit 977917475f
8 changed files with 3242 additions and 0 deletions

3
.babelrc Normal file

@ -0,0 +1,3 @@
{
"presets": ["latest"]
}

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

@ -0,0 +1,2 @@
node_modules
lib

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

@ -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

@ -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)];
};

@ -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);
});
});

3080
yarn.lock Normal file

File diff suppressed because it is too large Load Diff