Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <DIV STYLE="font-family:sans-serif;text-align:center">
  <small>(dr weird voice)</small>
  <H1>BEHOLD!</H1>
  <H1>INFINITE BIRDS!</H1>
</DIV>
              
            
!

CSS

              
                body{
  --bg:#fff;
  --text:#000;
  --border:rgba(0, 0, 0, 0.5);
  background:var(--bg);
  color:var(--text);
}
svg{
  shape-rendering:geometricPrecision;
}
.burd{
  width:90px;
  height:90px;
  border:solid 1px currentcolor;
  border-radius:1%;
  display:inline-block;
  overflow:hidden;
  margin:2px;
  z-index:1;
  position:relative;
  transition:all 0.2s ease-out;
  background:transparent;
}
.burd:hover{
  z-index:200;
  transform:scale(2.8);
  border-radius:100%;
  background:var(--bg);
}
              
            
!

JS

              
                // faster than sine?
var fakeSineDeg = function(x){
  x = x % 360
  var r = x % 180
  var sign = x-Math.abs(r) >= 180 ^ r < 0?-1:1
  //if (r < 0){sign*=-1}
  return 4*r*(180-r)/(40500-r*(180-r))*sign
}

// arcsine distrubution => more extremes
function prng(n){
  return (fakeSineDeg(n*5033482.1931782352824*180/Math.PI)+1)/2
}

function mix(v1,v2,a){
  var ret = []
  for (var i = 0; i < v1.length && i < v2.length; i++){
    ret.push( v1[i]*(1-a)+v2[i]*a )
  }
  return ret
}

class __Hsla{
  constructor(h,s,l,a){
    if (Array.isArray(h)){
      return this(h[0],h[1],h[2],h[3]);
    }
    this.h=h;
    this.s=s;
    this.l=l;
    this.a=(!a&&a!==0)?1:a;
  }
  toString(){
    return `hsla(${this.h},${this.s}%,${this.l}%,${this.a})`
  }
  get hue(){return this.h}
  get saturation(){return this.s}
  get lightness(){return this.l}
  get alpha(){return this.a}
  
}
function Hsla(){
  return new __Hsla(...arguments);
}

var strokeWidth = 1;

function getEye(n,position){
  var t = prng(n*3)
  var r = 8 - 3 * prng(n*5)
  var opts = [
    ()=> `<path d="M ${position[0]-r} ${position[1]-r/2} a ${r} ${r} 0 0 1 ${r*2} 0" fill="rgba(0,0,0,0)" stroke="${getLineColor(n)}" stroke-width="2"/>`,
    ()=> `<path d="M ${position[0]+r} ${position[1]-r/2} a ${r} ${r} 0 0 1 ${-r*2} 0" fill="rgba(0,0,0,0)" stroke="${getLineColor(n)}" stroke-width="2"/>`,
    ()=> `<circle cx="${position[0]-r}" cy="${position[1]}" r="${r}" fill="${getLineColor(n)}"/>`,
    ()=> `<circle cx="${position[0]-r}" cy="${position[1]}" r="${r}" stroke="${getLineColor(n)}" fill="${getLineColorInverse(n)}" stroke-width="2"/>`,
    ()=> `<circle cx="${position[0]-r}" cy="${position[1]}" r="${r}" stroke="${getLineColorInverse(n)}" fill="${getLineColor(n)}" stroke-width="2"/>`,
    ()=> `<path d="M ${position[0]-r} ${position[1]-r/2} l ${r} ${-r} l ${r} ${r}" stroke="${getLineColor(n)}" fill="none" stroke-width="2"/>`
  ]
  return opts[Math.floor(t*opts.length)]()
}

function getBeakBase(n){
  var b1 = prng(n+2)
  var b2 = prng(n+3)
  return [[70-b1*10,35],[70-b2*10,55]]
}

function getBeakTip(n){
  var up = prng(n*9.876)
  var over = prng(n*543.21)
  return [95-over*10,50-up*10]
}

function getBodyLightness(n){
  return getBirdColor(n).l
}

function getBirdColor(n){
  return Hsla(360*prng(n*1.25892+13),prng(n*31.52324)*100,prng(n*12.25494)*100)
}
// get color for lines... i.e. for eyes
function getLineColor(n){
  var bodyLightness = getBodyLightness(n)
  if (bodyLightness < 34){
    return '#eee'
  }else{
    return '#111'
  }
}
function getLineColorInverse(n){
  var bodyLightness = getBodyLightness(n)
  if (bodyLightness < 34){
    return '#111'
  }else{
    return '#fff'
  }
}

// get outline color for a bird's body
function getOutlineColor(n){
  var bodyLightness = getBodyLightness(n)
  if (bodyLightness < 50){
    return 'rgba(255,255,255,0.8)'
  }else{
    return 'rgba(0,0,0,0.8)'
  }
}

function getOutlineForColor(color){
  if (color.l < 50){
    return 'rgba(255,255,255,0.8)'
  }else{
    return 'rgba(0,0,0,0.8)'
  }
}
function getOutlineForColorInverse(color){
  var c = Hsla(color.h, color.s, 100 - color.l, color.a)
  return getOutlineColorForLightness(c)
}


function getBeakColor(n){
  // TODO have some black/gray beaks and outline them properly!
  return Hsla(prng(n*8.8642)*50+7,prng(n*2)*35+75,prng(n*4.4)*15+50)
}

function getBeak(n){
  var beakBase = getBeakBase(n)
  var beakTip = getBeakTip(n)
  var curvatureTop = prng(n*5432);
  var curvatureBottom = prng(n*4.315);
  var beakTipSwoop = prng(n*5.5454)
  var beakHeight = beakBase[1][1]-beakBase[0][1]
  
  // move to base top, then go to tip, then come back to bottom.
  return `<path d="M ${beakBase[0][0]} ${beakBase[0][1]} 
          c 0 0, ${beakTipSwoop*10} ${curvatureTop*-3}, ${beakTip[0]-beakBase[0][0]} ${beakTip[1]-beakBase[0][1]}
          c 0 ${beakTipSwoop*5}, ${-10*curvatureBottom} 0, ${beakBase[1][0]-beakTip[0]} ${beakBase[1][1]-beakTip[1]} z" 
          
          stroke="${getOutlineColor(n)}" fill="${getBeakColor(n)}" stroke-width="${strokeWidth}"/>`
}

function getPlumeColor(n){
  if (prng(n*0.532) > 0.3){return getBirdColor(n)}
  return Hsla(360*prng(n+175),prng(n*1783.2)*20+80,prng(n*43.134)*30+40)
}

function getCere(n){
  if (prng(n+1.11) < 0.9){return ''}
  
  var pos = mix(getBeakBase(n)[0], getBeakTip(n),0.25 * prng(n-4.32)+0.1);
  var r = prng(n*9.432)*2+3
  return `<circle cx="${pos[0]}" cy="${pos[1]}" r="${r}" fill="${getBeakColor(n)}" stroke="${getOutlineColor(n)}" stroke-width="${strokeWidth}"/>`
}
function getPlume(n){
  if (prng(n+0.9234) < 0.9){return ''}
  var tip = getHeadTop(n)
  var beakTop = getBeakBase(n)[0]
  var p0 = mix(tip,beakTop,0.2)
  // move base point up a bit
  p0[1]-=1;
  var p1 = mix(tip,beakTop,-0.9-0.7*prng(n+0.332))
  // back is halfway then dropped down
  var p2 = mix(p0,p1,0.7)
  p2 = [p2[0]-5,p2[1]+(5+5*prng(n-6.43))]
  var stroke = getOutlineColor(n)
  if (stroke == 'none'){stroke = getPlumeColor(n)}
  return `<path d="M ${p0[0]} ${p0[1]} L ${p1[0]} ${p1[1]} L ${p2[0]} ${p2[1]} z" fill="${getPlumeColor(n)}" stroke="${stroke}" stroke-width="${strokeWidth}"/>`
}

function getQuailPlume(n){
  if (prng(n+51.12) < 0.9){return ''}
  var tip = getHeadTop(n);
  var beakTop = getBeakBase(n)[0];
  var w = Math.abs(tip[0]-beakTop[0])
  var featherBase = [tip[0]-3, tip[1]+5]
  
  var ret = ''
  for (var i = 0; i < 2*prng(n*6.341); i ++){

    var featherEnd = [beakTop[0]-w/4-i*2, beakTop[1] *0.3 + i*12]
    var baseControlPoint = [tip[0], featherEnd[1]]
    var featherEndControlPoint = [featherEnd[0] - w/3, featherEnd[1] - w/3]

    ret += `<path d="M ${featherBase[0]} ${featherBase[1]} 
              C ${baseControlPoint[0]} ${baseControlPoint[1]}, 
              ${featherEndControlPoint[0]} ${featherEndControlPoint[1]}, 
              ${featherEnd[0]} ${featherEnd[1]}" 
              stroke="${getOutlineColor(n)}"  stroke-width="${8+strokeWidth*2}" fill="none"/>` +
      `<path d="M ${featherBase[0]} ${featherBase[1]} 
              C ${baseControlPoint[0]} ${baseControlPoint[1]}, 
              ${featherEndControlPoint[0]} ${featherEndControlPoint[1]}, 
              ${featherEnd[0]} ${featherEnd[1]}" 
              stroke="${getPlumeColor(n)}"  stroke-width="8" fill="none"/>`
  }
  
  return ret
}

function getTailPlume(n){
  
  if (prng(n*0.9136) > 0.2){return ''}
  var ret = ''
  var fill = (prng(n*0.8567) < 0.2) ? getPlumeColor(n) : getBirdColor(n)
  var len = prng(n*0.643) *2 +3
  for (var i = 0; i < len; i ++){
    var p0 = mix([0,0],getHeadTop(n),0.6)
    p0[0]+= 10
    p0[0] -= i*40/len
    p0[1] += i*10/len
    var p1 = [p0[0]-10,p0[1]-5]
    var p2 = [-10,70]
    var p3 = [-10,90]
    ret += `<path d="M ${p0[0]} ${p0[1]} L ${p1[0]} ${p1[1]} L ${p2[0]} ${p2[1]} L ${p3[0]} ${p3[1]} z" fill="${fill}" stroke="${getOutlineColor(n)}" stroke-width="${strokeWidth}"/>`
  }
  return ret
  
}

function getHeadTop(n){
  return [35 + 10*prng(n*3.26), 25 + 5* prng(1.23*n)]
}

function getBody(n){
  var beakBase = getBeakBase(n)
  // go over eye
  var top =  getHeadTop(n)
  var offsetX = 30 + 20 * prng(1234.5+n)
  var w = 80 - 30*prng(0.1234*n)
  var birdColor = getBirdColor(n)
  var csColor =   Hsla(360*prng(n+11),prng(n*65.52324)*100,prng(n*n*12.25494)*25+75,0.7)
  
  var smooth = prng(n*0.412) > 0.2;
  var smoothForward = smooth ? 5 : 0;  
  var smoothBackward = smooth ? 40 : 0;
  
  var beakTip = getBeakTip(n)
  var backBase = [offsetX + w/2, 103]
  
  var beakTopControlPoint = smooth?mix(beakBase[0],beakTip,-0.1):beakBase[0]
  var forwardControlPoint = smooth?mix(beakBase[0],top,1.6):top
  var backControlPoint = smooth?mix(forwardControlPoint,top,2.0):top
  if (smooth){backControlPoint[1] = top[1]}
  if (smooth){forwardControlPoint[1] = top[1]}


  var counterShaded = prng(n*43.1234976) > 0.75
  var counterShadeX = offsetX + w/3*prng(n+4*1)
  var cs = !counterShaded?'':`<path d="M ${beakBase[1][0]} ${beakBase[1][1]}
  L ${offsetX + w/2} 103
  L ${counterShadeX} 103" 
  stroke="${getOutlineColor(n)}" fill="${csColor}" stroke-width="${strokeWidth}"/>`
  
  return `<path d="M ${beakBase[0][0]} ${beakBase[0][1]} 
    C ${beakTopControlPoint[0]} ${beakTopControlPoint[1]}, ${backControlPoint[0]} ${backControlPoint[1]}, ${top[0]} ${top[1]} 
    C ${forwardControlPoint[0]} ${forwardControlPoint[1]}, ${offsetX - w/2} 103, ${offsetX - w/2} 103 
    L ${backBase[0]} ${backBase[1]}
    L ${beakBase[1][0]} ${beakBase[1][1]}"
    stroke="${getOutlineColor(n)}" fill="${birdColor}" stroke-width="${strokeWidth}"/>`+cs
}

// all params are 0..1
function genBird(seed){
  
  var str = 'a'
  var hash = str.split('').map(c=>c.charCodeAt(0)).reduce((val,accum)=>{return val + accum},0) //todo hash should be an actual hashing function
  var flip = prng(seed*0.9876) < 0.5 ? -1 : 1
  var tailPlume = getTailPlume(seed);
  return `<svg viewbox="5 0 90 90" xmlns="http://www.w3.org/2000/svg" style="transform:scale(${flip},1);">
        
        <g transform="translate(${tailPlume?'2':'0'},0)" stroke-linecap="round" stroke-linejoin="round"  stroke-width="${strokeWidth}">
          ${tailPlume}
          ${getQuailPlume(seed)}
          ${getBody(seed)}        
          ${getPlume(seed)}
          ${getBeak(seed)}
          ${getCere(seed)}
          ${getEye(seed,[50,50])}
        </g>

  </svg>`;
}

var g =0
function addBirds(){
  for (var i = 0; i < 1000; i++){
    var d = document.createElement('div')
    d.title=`genBird(${(i+g)/10})`

    d.setAttribute('class','burd')
    d.innerHTML = genBird((i+g)/10)
    document.body.appendChild(d)
    // var im = document.createElement('img');
    // im.src = 'data:image/svg;base64,'+btoa(d.innerHTML);
    // document.body.appendChild(im)
  }
  g+=1000
}

window.onscroll = function(ev) {
    if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight-100) {
        addBirds()
    }
};
addBirds()



var dark = false;
document.body.addEventListener('click',function(){
  dark = !dark;
  if (dark){
    document.body.style="--bg:#000;--text:#fff;--border:rgba(255,255,255,0.8);"
  } else{
    document.body.style="--bg:#fff;--text:#000;--border:rgba(0,0,0,0.8);"
  }
  
});
              
            
!
999px

Console