Prettier! More images, parallax, and subtle borders
| 
						 | 
				
			
			@ -4,6 +4,7 @@
 | 
			
		|||
<head>
 | 
			
		||||
    <meta charset="UTF-8" />
 | 
			
		||||
    <link rel="icon" type="image/png" href="/augustcircle.png" />
 | 
			
		||||
    <link rel="stylesheet" type="text/css" href="/style.css" />
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | 
			
		||||
    <title>ʕ·ᴥ·ʔ- august kline</title>
 | 
			
		||||
</head>
 | 
			
		||||
| 
						 | 
				
			
			@ -11,7 +12,7 @@
 | 
			
		|||
<body>
 | 
			
		||||
    <div id="app">
 | 
			
		||||
        <div class="text">
 | 
			
		||||
            <h1>ʕ·ᴥ·ʔ- hi! i'm august. or kline. </h1>
 | 
			
		||||
            <h1>hi! i'm august. or kline. </h1>
 | 
			
		||||
            <p>i like to build systems. lately i've been working on
 | 
			
		||||
                <a href="https://git.augustkline.com/august/george" target="_blank" rel="noreferer">george</a>.
 | 
			
		||||
                here's my
 | 
			
		||||
| 
						 | 
				
			
			@ -22,9 +23,11 @@
 | 
			
		|||
                <a href="mailto:august@klinegareth.com" target="_blank" rel="noreferer">email</a>
 | 
			
		||||
                (and my
 | 
			
		||||
                <a href="/augustklineResume.pdf" target="_blank" rel="noreferer">resume</a>
 | 
			
		||||
                if ur into that sorta thing)
 | 
			
		||||
                too!)
 | 
			
		||||
            </p>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div id="background">
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <script type="module" src="/src/main.ts"></script>
 | 
			
		||||
</body>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
		 After Width: | Height: | Size: 4.3 MiB  | 
| 
		 After Width: | Height: | Size: 7.3 MiB  | 
| 
		 After Width: | Height: | Size: 11 MiB  | 
| 
		 After Width: | Height: | Size: 3.4 MiB  | 
| 
		 After Width: | Height: | Size: 2.9 MiB  | 
| 
		 After Width: | Height: | Size: 2.2 MiB  | 
| 
		 After Width: | Height: | Size: 938 KiB  | 
| 
		 After Width: | Height: | Size: 11 MiB  | 
| 
		 After Width: | Height: | Size: 1.5 MiB  | 
| 
		 After Width: | Height: | Size: 128 KiB  | 
| 
		 After Width: | Height: | Size: 514 KiB  | 
							
								
								
									
										113
									
								
								src/main.ts
								
								
								
								
							
							
						
						| 
						 | 
				
			
			@ -1,4 +1,3 @@
 | 
			
		|||
import "./style.css";
 | 
			
		||||
import backwalkgeorge from "/backwalkgeorge.jpg";
 | 
			
		||||
import georgetoilet from "/georgetoilet.png";
 | 
			
		||||
import klinefloor from "/klinefloor.jpeg";
 | 
			
		||||
| 
						 | 
				
			
			@ -8,11 +7,27 @@ import klinetrain from "/klinetrain.jpeg";
 | 
			
		|||
import sashaklineburrito from "/sashaklineburrito.jpeg";
 | 
			
		||||
import sashaklinecar from "/sashaklinecar.jpeg";
 | 
			
		||||
import sunsetkline from "/sunsetkline.png";
 | 
			
		||||
import georgerasp from "/georgerasp.gif";
 | 
			
		||||
import sunsetfourteenth from "/14thstsunrise.gif";
 | 
			
		||||
import solderkitty from "/solderkitty.jpeg";
 | 
			
		||||
import ducklings from "/ducklings.gif";
 | 
			
		||||
import fieldnotes from "/fieldnotes.gif";
 | 
			
		||||
import lamp from "/lamp.gif";
 | 
			
		||||
import ohio from "/ohio.jpeg";
 | 
			
		||||
import heron from "/heron.jpeg";
 | 
			
		||||
import flowers from "/flowers.jpeg";
 | 
			
		||||
import mirror from "/mirror.jpeg";
 | 
			
		||||
 | 
			
		||||
let app = document.getElementById("app")!;
 | 
			
		||||
let background = document.getElementById("background")!;
 | 
			
		||||
 | 
			
		||||
let prefersReducedMotion = window.matchMedia(
 | 
			
		||||
  "(prefers-reduced-motion: reduce)",
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
let setImages = () => {
 | 
			
		||||
  let images = [
 | 
			
		||||
  let images: string[] = [];
 | 
			
		||||
  if (prefersReducedMotion.matches) {
 | 
			
		||||
    images = [
 | 
			
		||||
      backwalkgeorge,
 | 
			
		||||
      georgetoilet,
 | 
			
		||||
      klinefloor,
 | 
			
		||||
| 
						 | 
				
			
			@ -22,14 +37,100 @@ let setImages = () => {
 | 
			
		|||
      sashaklineburrito,
 | 
			
		||||
      sashaklinecar,
 | 
			
		||||
      sunsetkline,
 | 
			
		||||
      // georgerasp,
 | 
			
		||||
      // sunsetfourteenth,
 | 
			
		||||
      solderkitty,
 | 
			
		||||
      // ducklings,
 | 
			
		||||
      fieldnotes,
 | 
			
		||||
      // lamp,
 | 
			
		||||
      ohio,
 | 
			
		||||
      heron,
 | 
			
		||||
      flowers,
 | 
			
		||||
      mirror,
 | 
			
		||||
    ];
 | 
			
		||||
  } else {
 | 
			
		||||
    images = [
 | 
			
		||||
      backwalkgeorge,
 | 
			
		||||
      georgetoilet,
 | 
			
		||||
      klinefloor,
 | 
			
		||||
      klinemirror,
 | 
			
		||||
      klineoutside,
 | 
			
		||||
      klinetrain,
 | 
			
		||||
      sashaklineburrito,
 | 
			
		||||
      sashaklinecar,
 | 
			
		||||
      sunsetkline,
 | 
			
		||||
      georgerasp,
 | 
			
		||||
      sunsetfourteenth,
 | 
			
		||||
      solderkitty,
 | 
			
		||||
      ducklings,
 | 
			
		||||
      fieldnotes,
 | 
			
		||||
      lamp,
 | 
			
		||||
      ohio,
 | 
			
		||||
      heron,
 | 
			
		||||
      flowers,
 | 
			
		||||
      mirror,
 | 
			
		||||
    ];
 | 
			
		||||
  }
 | 
			
		||||
  const randn_bm = (mean = 0, stdev = 0.4) => {
 | 
			
		||||
    const u = 1 - Math.random();
 | 
			
		||||
    const v = Math.random();
 | 
			
		||||
    const z = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);
 | 
			
		||||
    return z * stdev + mean;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const randNums = (count: number, minDistance: number): number[] => {
 | 
			
		||||
    const numbers: number[] = [];
 | 
			
		||||
 | 
			
		||||
    function isFarEnough(num: number): boolean {
 | 
			
		||||
      for (const n of numbers) {
 | 
			
		||||
        if (Math.abs(num - n) < minDistance) {
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while (numbers.length < count) {
 | 
			
		||||
      const newNumber = randn_bm();
 | 
			
		||||
      if (isFarEnough(newNumber)) {
 | 
			
		||||
        numbers.push(newNumber);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return numbers;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const lefts = randNums(images.length, 0.05);
 | 
			
		||||
  const tops = randNums(images.length, 0.05);
 | 
			
		||||
  for (let index in images) {
 | 
			
		||||
    let img = document.createElement("img");
 | 
			
		||||
    img.setAttribute("src", images[index]);
 | 
			
		||||
    img.style.setProperty("left", (Math.random() * 100).toString() + "%");
 | 
			
		||||
    img.style.setProperty("top", (Math.random() * 100).toString() + "%");
 | 
			
		||||
    app.append(img);
 | 
			
		||||
    // let left = randn_bm();
 | 
			
		||||
    // let top = randn_bm();
 | 
			
		||||
    let left = lefts[index];
 | 
			
		||||
    let top = tops[index];
 | 
			
		||||
    let z = (Math.abs(left) + Math.abs(top)) / 2;
 | 
			
		||||
    let range = { x: window.innerWidth * 0.7, y: window.innerHeight * 0.7 };
 | 
			
		||||
    img.style.setProperty(
 | 
			
		||||
      "left",
 | 
			
		||||
      `${left * range.x + window.innerWidth / 2}px`,
 | 
			
		||||
    );
 | 
			
		||||
    img.style.setProperty("top", `${top * range.y + window.innerHeight / 2}px`);
 | 
			
		||||
    img.style.setProperty("--translate-z", `${z * 3000}px`);
 | 
			
		||||
    img.setAttribute("data-group", `${Math.floor(Math.random() * 3)}`);
 | 
			
		||||
    background.append(img);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const root = document.documentElement;
 | 
			
		||||
 | 
			
		||||
const onMove = (ev: MouseEvent) => {
 | 
			
		||||
  let rotateY = `${(ev.clientX - window.innerWidth / 2) * 0.001}deg`;
 | 
			
		||||
  let rotateX = `${(ev.clientY - window.innerHeight / 2) * 0.001}deg`;
 | 
			
		||||
  root.style.setProperty("--rotate-x", rotateX);
 | 
			
		||||
  root.style.setProperty("--rotate-y", rotateY);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
document.addEventListener("mousemove", onMove);
 | 
			
		||||
 | 
			
		||||
setImages();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,77 +0,0 @@
 | 
			
		|||
:root {
 | 
			
		||||
    font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
 | 
			
		||||
    line-height: 1.5;
 | 
			
		||||
    font-weight: 400;
 | 
			
		||||
    color: var(--text-color);
 | 
			
		||||
    font-synthesis: none;
 | 
			
		||||
    text-rendering: optimizeLegibility;
 | 
			
		||||
    -webkit-font-smoothing: antialiased;
 | 
			
		||||
    -moz-osx-font-smoothing: grayscale;
 | 
			
		||||
    --link-color: oklch(68% .1707 0);
 | 
			
		||||
    --text-color: black
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
body,
 | 
			
		||||
html {
 | 
			
		||||
    inline-size: 100%;
 | 
			
		||||
    block-size: 100%;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    padding: 0;
 | 
			
		||||
    overflow: hidden
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#app {
 | 
			
		||||
    inline-size: 100%;
 | 
			
		||||
    block-size: 100%;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    padding: 0;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    overflow: hidden
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
h1 {
 | 
			
		||||
    font-size: 1.5rem;
 | 
			
		||||
    margin-block: .5rem
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
p {
 | 
			
		||||
    font-size: 1.5rem;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    text-align: justify;
 | 
			
		||||
    inline-size: 100%
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a {
 | 
			
		||||
    color: var(--link-color);
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    transition: .2s text-shadow, .2s transform;
 | 
			
		||||
    display: inline-block
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a:hover {
 | 
			
		||||
    text-shadow: 0rem 0rem 1rem var(--link-color);
 | 
			
		||||
    transform: rotate(-3deg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
img {
 | 
			
		||||
    transform: translate(-50%, -50%);
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    inline-size: 10%;
 | 
			
		||||
    z-index: -1;
 | 
			
		||||
    min-inline-size: 10rem
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.text {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    background: #fff;
 | 
			
		||||
    border: 1px solid black;
 | 
			
		||||
    box-shadow: 0 0 1.5rem #fff;
 | 
			
		||||
    padding: .8rem 1.6rem;
 | 
			
		||||
    inline-size: clamp(20rem, 30%, 40rem)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,125 @@
 | 
			
		|||
:root {
 | 
			
		||||
    font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
 | 
			
		||||
    line-height: 1.5;
 | 
			
		||||
    font-weight: 400;
 | 
			
		||||
    color: var(--text-color);
 | 
			
		||||
    font-synthesis: none;
 | 
			
		||||
    text-rendering: optimizeLegibility;
 | 
			
		||||
    -webkit-font-smoothing: antialiased;
 | 
			
		||||
    -moz-osx-font-smoothing: grayscale;
 | 
			
		||||
    --text-color: black;
 | 
			
		||||
    --link-color: var(--text-color);
 | 
			
		||||
    --link-shadow-color: rgba(0, 0, 0, 0.5);
 | 
			
		||||
    --border-color: rgba(200, 200, 200, 0.5);
 | 
			
		||||
    --text-bg-color: rgba(255, 255, 255, 0.9);
 | 
			
		||||
    --text-border-shadow-color: rgba(255, 255, 255, 0.7);
 | 
			
		||||
    --text-shadow-color: rgba(0, 0, 0, 0.1);
 | 
			
		||||
    --img-bg-color: rgba(50, 50, 50, 0.2);
 | 
			
		||||
    --img-border-color: rgba(255, 255, 255, 0.8);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
body,
 | 
			
		||||
html {
 | 
			
		||||
    inline-size: 100%;
 | 
			
		||||
    block-size: 100%;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    padding: 0;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#app {
 | 
			
		||||
    inline-size: 100%;
 | 
			
		||||
    block-size: 100%;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    padding: 0;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
h1 {
 | 
			
		||||
    font-size: 1.5rem;
 | 
			
		||||
    margin-block: .5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
p {
 | 
			
		||||
    font-size: 1.5rem;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    text-align: justify;
 | 
			
		||||
    text-align-last: center;
 | 
			
		||||
    inline-size: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a {
 | 
			
		||||
    color: var(--link-color);
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    transition: .2s text-shadow, .2s transform;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    font-weight: 600;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a:hover {
 | 
			
		||||
    text-shadow: 0rem 0.2rem 1rem var(--link-shadow-color);
 | 
			
		||||
    /* transform: rotate(-3deg); */
 | 
			
		||||
    transform: translateY(-7%) scale(1.01);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
img {
 | 
			
		||||
    transform: translate(-50%, -50%) translateZ(var(--translate-z));
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    inline-size: 10%;
 | 
			
		||||
    z-index: -1;
 | 
			
		||||
    min-inline-size: 10rem;
 | 
			
		||||
    border: 0.01rem solid var(--img-border-color);
 | 
			
		||||
    border-radius: 1rem;
 | 
			
		||||
    box-shadow: 0.05rem 0.05rem 0px var(--img-bg-color),
 | 
			
		||||
        -0.05rem -0.05rem 0px var(--img-bg-color),
 | 
			
		||||
        0.05rem -0.05rem 0px var(--img-bg-color),
 | 
			
		||||
        -0.05rem 0.05rem 0px var(--img-bg-color),
 | 
			
		||||
        0 0 1rem rgba(0, 0, 0, 0.3);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#background {
 | 
			
		||||
    transform-style: preserve-3d;
 | 
			
		||||
    transform: rotateX(var(--rotate-x)) rotateY(var(--rotate-y));
 | 
			
		||||
    inline-size: 100%;
 | 
			
		||||
    block-size: 100%;
 | 
			
		||||
    z-index: -1;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (prefers-reduced-motion: reduce) {
 | 
			
		||||
    #background {
 | 
			
		||||
        transform: none;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    a {
 | 
			
		||||
        transition: none;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    a:hover {
 | 
			
		||||
        transform: none;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.text {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    background: var(--text-bg-color);
 | 
			
		||||
    backdrop-filter: blur(10px);
 | 
			
		||||
    -webkit-backdrop-filter: blur(10px);
 | 
			
		||||
    border: 0.01rem solid var(--border-color);
 | 
			
		||||
    margin: 1px;
 | 
			
		||||
    padding: .8rem 1.6rem;
 | 
			
		||||
    inline-size: clamp(20rem, 30%, 40rem);
 | 
			
		||||
    border-radius: 1rem;
 | 
			
		||||
    box-shadow: 0.05rem 0.05rem 0px var(--text-border-shadow-color),
 | 
			
		||||
        -0.05rem -0.05rem 0px var(--text-border-shadow-color),
 | 
			
		||||
        0.05rem -0.05rem 0px var(--text-border-shadow-color),
 | 
			
		||||
        -0.05rem 0.05rem 0px var(--text-border-shadow-color),
 | 
			
		||||
        0rem 0rem 2rem var(--text-shadow-color);
 | 
			
		||||
}
 | 
			
		||||