-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f3222f8
commit dd4bd23
Showing
7 changed files
with
173 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { render } from 'svelte/server'; | ||
import Background from '$lib/components/Background.svelte'; | ||
|
||
let WIDTH_HEADERS = ["Width", "Viewport-Width", "Sec-CH-Width", "Sec-CH-Viewport-Width"]; | ||
let HEIGHT_HEADERS = ["Sec-CH-Viewport-Height"]; | ||
let MOBILE_INDICATORS = ["mobile", "android", "iphone"] | ||
|
||
export default async ({ request }: { request: Request }) => { | ||
// Try detect viewport height | ||
let width = 1920; | ||
|
||
for (const header of WIDTH_HEADERS) { | ||
const headerContent = request.headers.get(header) | ||
if (headerContent !== null) { | ||
const newWidth = parseInt(headerContent); | ||
|
||
if (isFinite(newWidth) && newWidth > 200) { | ||
width = parseInt(headerContent) | ||
console.log(`Detected width: ${width}`) | ||
break | ||
} | ||
} | ||
} | ||
|
||
// Now try detect viewport width | ||
let height = null; | ||
|
||
for (const header of HEIGHT_HEADERS) { | ||
const headerContent = request.headers.get(header) | ||
if (headerContent !== null) { | ||
const newHeight = parseInt(headerContent); | ||
|
||
if (isFinite(newHeight) && newHeight > 200) { | ||
height = parseInt(headerContent) | ||
console.log(`Detected height: ${height}`) | ||
break | ||
} | ||
} | ||
} | ||
|
||
// If that fails, try detect whether it is mobile and derive an aspect ratio from that | ||
if (height == null) { | ||
let aspectRatio = 0.5625; | ||
|
||
const userAgent = request.headers.get("User-Agent") | ||
if (userAgent !== null) { | ||
for (const indicator of MOBILE_INDICATORS) { | ||
if (userAgent.toLowerCase().includes(indicator)) { | ||
aspectRatio ^= -1 | ||
break | ||
} | ||
} | ||
} | ||
|
||
height = width * aspectRatio | ||
console.log(`Derived height: ${height}`) | ||
} | ||
|
||
// Now render the background and return it | ||
// Create an insecure random seed from the request headers | ||
const seed = Array.from([...request.headers].join('')) | ||
.reduce((hash, char) => 0 | (31 * hash + char.charCodeAt(0)), 0) | ||
const svg = render(Background, { | ||
props: { width, height, seed } | ||
}) | ||
|
||
// Evil | ||
let body = svg.body.replaceAll(/<!--[\[\]]?!?\??-->/g, "") | ||
|
||
return new Response(body, { | ||
status: 200, | ||
headers: { | ||
"Vary": "Width, Viewport-Width, Sec-CH-Width, Sec-CH-Viewport-Width, Sec-CH-Viewport-Height, Sec-CH-UA-Mobile", | ||
"Content-Type": "image/svg+xml" | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<script lang="ts"> | ||
export let width: number; | ||
export let height: number; | ||
export let seed: number; | ||
let boxWidth = Math.ceil(width / 32); | ||
let boxHeight = Math.ceil(height / 16); | ||
// Perlin code derived from https://github.com/joeiddon/perlin/blob/master/perlin.js | ||
// Generate a somewhat random vector with the SplitMix32 algorithm | ||
function random() { | ||
seed |= 0; | ||
seed = seed + 0x9e3779b9 | 0; | ||
let t = seed ^ seed >>> 16; | ||
t = Math.imul(t, 0x21f0aaad); | ||
t = t ^ t >>> 15; | ||
t = Math.imul(t, 0x735a2d97); | ||
let value = (((t = t ^ t >>> 15) >>> 0) / 4294967296) * 2 * Math.PI | ||
return {x: Math.cos(value), y: Math.sin(value)} | ||
} | ||
function dotProductGrid(x: number, y: number, vx: number, vy: number) { | ||
let gVector = random(); | ||
let dVector = {x: x - vx, y: y - vy}; | ||
return dVector.x * gVector.x + dVector.y * gVector.y | ||
} | ||
function interpolate(x: number, a: number, b: number) { | ||
return a + (6*x**5 - 15*x**4 + 10*x**3) * (b-a) | ||
} | ||
// This function assumes it will be called once per pair. | ||
// As such, it does no memoization at all. | ||
function evaluateAt(x: number, y: number) { | ||
let xf = Math.floor(x); | ||
let yf = Math.floor(y); | ||
let tl = dotProductGrid(x, y, xf, yf); | ||
let tr = dotProductGrid(x, y, xf+1, yf); | ||
let bl = dotProductGrid(x, y, xf, yf+1); | ||
let br = dotProductGrid(x, y, xf+1, yf+1); | ||
let xt = interpolate(x-xf, tl, tr); | ||
let xb = interpolate(x-xf, bl, br); | ||
let v = interpolate(y-yf, xt, xb); | ||
return v; | ||
} | ||
</script> | ||
|
||
<svelte:options namespace="svg" /> | ||
|
||
<svg xmlns="http://www.w3.org/2000/svg" width={width} height={height} viewBox="0 0 {width} {height}"> | ||
<metadata> | ||
<seed>{seed}</seed> | ||
<width>{width}</width> | ||
<height>{height}</height> | ||
</metadata> | ||
<defs> | ||
<rect id="r" fill="black" width="31" height="15" /> | ||
</defs> | ||
{#each Array(boxHeight) as _, y} | ||
{#each Array(boxWidth) as _, x} | ||
{@const opacity = (evaluateAt(x/64, y/32) / 4) - 0.01} | ||
{#if opacity > 0} | ||
<use href="#r" y={y * 16} x={x * 32 - ((y % 2) * 16)} fill-opacity={opacity} /> | ||
{/if} | ||
{/each} | ||
{/each} | ||
</svg> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import handler from '$lib/background'; | ||
|
||
export const GET = handler; |