<css-doodle id="myDoodle">
:doodle {
@grid: 36 / 100%;
background-color: blue;
}
mix-blend-mode: difference;
:after {
font-size:@r(1vmax, 4vmax);
font-family:Saira Stencil One;
content:\@hex(@pd(65,97));
color: @pd(#906131,#313190,#313190,#7f9031,#506eaf);
transform: skew(0deg) scale(1) rotate(-45deg);
}
</css-doodle>
body {
width: 100vmax;
height: 100vmax;
background-color: black;
overflow: hidden;
padding: 0px;
margin: 0px;
filter: grayscale(90);
}
(function () {
const characterSets = {
key: "As",
ranges: [
{ min: 0x0041, max: 0x0041 }, /* basic latin "A" */
{ min: 0x0061, max: 0x0061 }, /* basic latin 'a' */
{ min: 0x0100, max: 0x0105 }, /* a's from latin extended A */
{ min: 0x01DE, max: 0x01E1 }, /* a's from latin extended B */
{ min: 0x2C6F, max: 0x2C6F }, /* a's from latin extended C */
{ min: 0x1EA2, max: 0x1EB7 }, /* a's from latin ext additional */
]
}
const paletteFuncs = [spectrum, triads, analogs, splitComplements, complements]
const blendModes = ["normal", "difference", "multiply", "exclusion", "hard-light", "luminosity"]
const rotations = ["@pd(0, 45deg, -45deg, 90deg, -90deg, 180deg)", "@pn(0, 45deg, 90deg, 180deg, -90deg, -45deg)", "@r(360deg)", "45deg", "-45deg", "0", "@pd(0, 180deg)", "@pd(0, 10deg, 20deg, 30deg, 40deg, 50deg, 60deg, 70deg, 80deg, 90deg)", "@pn(0, 10deg, 20deg, 30deg, 40deg, 50deg, 60deg, 70deg, 80deg, 90deg)", "@pn(0, -10deg, -20deg, -30deg, -40deg, -50deg, -60deg, -70deg, -80deg, -90deg)", "@pn(0, 15deg, 30deg, 45deg, 60deg, 75deg, 90deg, 105deg, 120deg, 135deg, 150deg, 165deg, 180deg)", "@pd(-90deg, 90deg)", "@pd(45deg, -135deg)", "@pd(-45deg, 135deg)"]
const API_KEY = "AIzaSyBySDtOFjhW9moTHVy6qc2gcshwzTTGiDA"
var Fonts = []
var selectedFonts = []
/*INITIALIZE*/
async function main() {
Fonts = await loadFontsList()
var dood = document.querySelector("#myDoodle")
dood.addEventListener("click", function(e) {
let fontMultiplier = getRandomIntInclusive(1,3)
selectedFonts = []
for(let i = 0; i<fontMultiplier; i++){
let thisFont = loadRandomFont()
selectedFonts.push(thisFont)
}
dood.update(characters())
})
}
main()
/* HELPER FUNCTIONS */
/* main generator function */
function characters() {
//fonts
let fontSize = Math.random() > .5 ? "2vmax" : `@r(1vmax, 4vmax)`
let fr = Math.random()
let fontPicker = fr > .66 ? "@pd" : fr > .33 ? "@p" : "@pn"
fontFamily = `${fontPicker}(${selectedFonts})`
//characters (All A's all the time)
let myChars = []
myChars.ranges = Math.random()>.5 ? characterSets.ranges : [characterSets.ranges[0], characterSets.ranges[1]]
if(Math.random()>.5){
myChars.ranges = [myChars.ranges[0], myChars.ranges[1]]
}
let set = flatten(myChars)
let pr = Math.random()
let picker = pr > .66 ? "@p" : pr > .33 ? "@pd" : "@pn"
if (Math.random() > .5) { //whole set or usually, a slice/selection of set
let num = getRandomIntInclusive(1, 3)
set = Math.random() > .5 ? randomPicks(set, num) : randomSlice(set, num)
}
let codeSelector = `\\@hex(${picker}(${set}))`
//rotation, blend modes, other affectations
let rotation = pick(rotations)
let blendModePicker = Math.random() > .5 ? "@p" : "@pd"
r = Math.random()
let myBlends = r > .66 ? randomSlice(blendModes) : r > .33 ? randomPicks(blendModes) : blendModes
let mixBlendMode = Math.random() > .5 ? `${blendModePicker}(${myBlends})` : pick(blendModes)
let scale = Math.random > .5 ? "@r(.5, 2.2)" : getRandomIntInclusive(.5, 2.2)
let skew = Math.random() > .5 ? getRandomIntInclusive(-40, 40) : 0
return `:doodle {
@grid: ${getRandomIntInclusive(10,40)} / 100%;
background-color:@p(blue, green, red, yellow, pink, cyan, orange, purple);
}
mix-blend-mode: ${mixBlendMode};
:after {
font-size:${fontSize};
font-family:${fontFamily};
content:${codeSelector};
color: ${Math.random() > .5 ? "@p" : "@pd"}(${getPalette()});
transform: skew(${skew}deg) scale(${scale}) rotate(${rotation});
}`
}
async function loadFontsList() {
try {
const result = await fetch('https://www.googleapis.com/webfonts/v1/webfonts?key=' + API_KEY);
const data = await result.json();
return data.items;
} catch (error) {
console.log('loadFontsList', error, error.message);
}
}
function loadRandomFont() {
const index = Math.floor(Math.random() * Fonts.length);
const chosenFont = Fonts[index].family;
WebFont.load({
google: {
families: [chosenFont]
}
});
return chosenFont;
}
function getPalette(seed, palette) {
if (!palette) palette = pick(paletteFuncs)
if (!seed) seed = getRandomColor()
return palette(seed)
}
function getRandomColor() {
let hue = Math.floor(Math.random() * 360)
let saturation = Math.floor(Math.random() * (100 - 30) + 30)
return tinycolor(`hsl(${hue}, ${saturation}, 50%)`)
}
function pick(arr) {
return arr[Math.floor(Math.random() * arr.length)]
}
function randomSlice(arr, num) {
num = num || getRandomIntInclusive(1, arr.length)
let start = getRandomIntInclusive(0, arr.length - 1)
while (start + num > arr.length) {
start--
}
return arr.slice(start, start + num)
}
function randomPicks(arr, num) {
num = num || getRandomIntInclusive(1, arr.length)
let picks = []
for (let i = 0; i < num; i++) {
picks.push(pick(arr))
}
return picks
}
function getRandomIntInclusive(min, max) {
min = Math.ceil(min)
max = Math.floor(max)
return Math.floor(Math.random() * (max - min + 1)) + min
}
function flatten(set) {
let flat = []
let ranges = set.ranges || [{
min: set.min,
max: set.max
}]
ranges.forEach(range => {
for (let i = range.min; i <= range.max; i++) {
flat.push(i)
}
})
return flat
}
/*palette functions (overkill for rotating some hues around before applying grayscale filter)*/
function spectrum(seed) {
let c1 = tinycolor(seed).spin(getRandomIntInclusive(-160, -130)).toHexString()
let c2 = tinycolor(seed).spin(getRandomIntInclusive(-92, -52)).toHexString()
let c3 = seed.toHexString()
let c4 = tinycolor(seed).spin(getRandomIntInclusive(52, 92)).toHexString()
let c5 = tinycolor(seed).spin(getRandomIntInclusive(130, 160)).toHexString()
return [c1, c2, c3, c4, c5]
}
function triads(seed) {
let smallRando = getRandomIntInclusive(5, 25)
let c1 = tinycolor(seed).desaturate(smallRando).lighten(smallRando).toHexString()
let c2 = tinycolor(seed).spin(getRandomIntInclusive(-150, -90)).toHexString()
let c3 = seed.toHexString()
let c4 = tinycolor(seed).spin(120).toHexString()
let c5 = tinycolor(seed).spin(getRandomIntInclusive(90, 150)).saturate(smallRando).darken(smallRando).toHexString()
return [c1, c2, c3, c4, c5]
}
function analogs(seed) {
let smallRando = getRandomIntInclusive(0, 20)
let c1 = tinycolor(seed).spin(getRandomIntInclusive(-30, -15)).toHexString()
let c2 = tinycolor(seed).spin(getRandomIntInclusive(-15, 0)).saturate(smallRando).darken(smallRando).toHexString()
let c3 = seed.toHexString()
let c4 = tinycolor(seed).spin(getRandomIntInclusive(0, 15)).desaturate(smallRando).lighten(smallRando).toHexString()
let c5 = tinycolor(seed).spin(getRandomIntInclusive(15, 30)).toHexString()
return [c1, c2, c3, c4, c5]
}
function splitComplements(seed) {
let smallRando = getRandomIntInclusive(0, 20)
let c1 = tinycolor(seed).spin(getRandomIntInclusive(-180, -130)).saturate(smallRando).darken(smallRando).toHexString()
let c2 = tinycolor(seed).spin(-150).toHexString()
let c3 = seed.toHexString()
let c4 = tinycolor(seed).spin(getRandomIntInclusive(-180, -130)).toHexString()
let c5 = tinycolor(seed).spin(150).desaturate(smallRando).lighten(smallRando).toHexString()
return [c1, c2, c3, c4, c5]
}
function complements(seed) {
let isDark = tinycolor(seed).isDark()
let c1 = tinycolor(seed).saturate(getRandomIntInclusive(5, 15)).darken(getRandomIntInclusive(10, 20)).toHexString()
let c2 = tinycolor(seed).desaturate(getRandomIntInclusive(0, 20)).lighten(getRandomIntInclusive(5, 25)).toHexString()
let c3 = seed.toHexString()
let c4 = tinycolor(seed).spin(180).toHexString()
let c5 = isDark ? tinycolor(seed).spin(getRandomIntInclusive(160, 200)).desaturate(getRandomIntInclusive(5, 15)).lighten(getRandomIntInclusive(10, 20)).toHexString() :
tinycolor(seed).spin(getRandomIntInclusive(160, 200)).saturate(getRandomIntInclusive(0, 20)).darken(getRandomIntInclusive(10, 20)).toHexString()
return [c1, c2, c3, c4, c5]
}
})("sweaverD.com")
This Pen doesn't use any external CSS resources.