background

This commit is contained in:
F53 2023-11-09 15:14:37 -07:00
parent 675354d7c4
commit d482c3a0ea
12 changed files with 228 additions and 3 deletions

10
.vscode/settings.json vendored
View file

@ -35,5 +35,13 @@
"json", "json",
"jsonc", "jsonc",
"yaml" "yaml"
] ],
// volar as formatter
"[vue]": {
"editor.defaultFormatter": "Vue.volar"
},
"[typescript]": {
"editor.defaultFormatter": "Vue.volar"
}
} }

View file

@ -1,4 +1,5 @@
<template> <template>
<Background />
<NuxtLayout> <NuxtLayout>
<NuxtPage /> <NuxtPage />
</NuxtLayout> </NuxtLayout>

View file

@ -1,5 +1,8 @@
// dark! // dark!
:root { color-scheme: dark; } :root {
color-scheme: dark;
background-color: #0c0c0c;
}
// logical sizing // logical sizing
* { box-sizing: border-box; } * { box-sizing: border-box; }

34
components/Background.vue Normal file
View file

@ -0,0 +1,34 @@
<script setup lang="ts">
const canvas: Ref<undefined | HTMLCanvasElement> = ref()
const intervalId: Ref<undefined | NodeJS.Timeout> = ref()
onMounted(() => {
if (!canvas.value)
return
initCanvas(canvas.value)
initPoints()
intervalId.value = setInterval(renderFrame, 8)
addEventListener('resize', useDebounce(handleResize, 250))
})
onBeforeUnmount(() => {
if (intervalId.value)
clearInterval(intervalId.value)
})
</script>
<template>
<canvas id="background" ref="canvas" />
</template>
<style lang="scss">
#background {
position: absolute;
top: 0; left: 0;
width: 100vw;
height: 100vh;
z-index: -1;
filter: blur(.5rem);
}
</style>

View file

@ -2,6 +2,7 @@
export default defineNuxtConfig({ export default defineNuxtConfig({
devtools: { enabled: true }, devtools: { enabled: true },
typescript: { strict: true, typeCheck: true, shim: false }, typescript: { strict: true, typeCheck: true, shim: false },
modules: ['nuxt-lodash'],
css: ['~/assets/styles/layout.scss', '~/assets/styles/misc.scss', '~/assets/styles/font.scss'], css: ['~/assets/styles/layout.scss', '~/assets/styles/misc.scss', '~/assets/styles/font.scss'],

33
package-lock.json generated
View file

@ -16,6 +16,7 @@
"eslint": "^8.52.0", "eslint": "^8.52.0",
"lint-staged": "^15.0.2", "lint-staged": "^15.0.2",
"nuxt": "^3.8.0", "nuxt": "^3.8.0",
"nuxt-lodash": "^2.5.3",
"simple-git-hooks": "^2.9.0", "simple-git-hooks": "^2.9.0",
"typescript": "^5.2.2", "typescript": "^5.2.2",
"vue": "^3.3.7", "vue": "^3.3.7",
@ -2817,6 +2818,21 @@
"integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==",
"dev": true "dev": true
}, },
"node_modules/@types/lodash": {
"version": "4.14.200",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.200.tgz",
"integrity": "sha512-YI/M/4HRImtNf3pJgbF+W6FrXovqj+T+/HpENLTooK9PnkacBsDpeP3IpHab40CClUfhNmdM2WTNP2sa2dni5Q==",
"dev": true
},
"node_modules/@types/lodash-es": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.10.tgz",
"integrity": "sha512-YJP+w/2khSBwbUSFdGsSqmDvmnN3cCKoPOL7Zjle6s30ZtemkkqhjVfFqGwPN7ASil5VyjE2GtyU/yqYY6mC0A==",
"dev": true,
"dependencies": {
"@types/lodash": "*"
}
},
"node_modules/@types/mdast": { "node_modules/@types/mdast": {
"version": "3.0.14", "version": "3.0.14",
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.14.tgz", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.14.tgz",
@ -8458,6 +8474,12 @@
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true "dev": true
}, },
"node_modules/lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
"dev": true
},
"node_modules/lodash.debounce": { "node_modules/lodash.debounce": {
"version": "4.0.8", "version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
@ -9730,6 +9752,17 @@
} }
} }
}, },
"node_modules/nuxt-lodash": {
"version": "2.5.3",
"resolved": "https://registry.npmjs.org/nuxt-lodash/-/nuxt-lodash-2.5.3.tgz",
"integrity": "sha512-LCJ40tGQTHkfk8rQoGqtb0mFgRVt8U+pc3S352DsI39yF3olqgxlsm28wdJMIcWHuxLgf5X+DwxmZhrAHXNS5g==",
"dev": true,
"dependencies": {
"@nuxt/kit": "^3.8.0",
"@types/lodash-es": "^4.17.10",
"lodash-es": "^4.17.21"
}
},
"node_modules/nuxt/node_modules/acorn": { "node_modules/nuxt/node_modules/acorn": {
"version": "8.10.0", "version": "8.10.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",

View file

@ -21,6 +21,7 @@
"eslint": "^8.52.0", "eslint": "^8.52.0",
"lint-staged": "^15.0.2", "lint-staged": "^15.0.2",
"nuxt": "^3.8.0", "nuxt": "^3.8.0",
"nuxt-lodash": "^2.5.3",
"simple-git-hooks": "^2.9.0", "simple-git-hooks": "^2.9.0",
"typescript": "^5.2.2", "typescript": "^5.2.2",
"vue": "^3.3.7", "vue": "^3.3.7",

View file

@ -35,7 +35,8 @@
<div> <div>
<h2>TODO:</h2> <h2>TODO:</h2>
<ul> <ul>
<li>background: pointcloud + something fancy with mouse movement + parallax scroll</li> <li>background: optimize render</li>
<li>background: something fancy with mouse movement</li>
<li>colors</li> <li>colors</li>
<li>experience page: (education + jobs + projects) handled with markdown, click to learn more, filterable, sortable</li> <li>experience page: (education + jobs + projects) handled with markdown, click to learn more, filterable, sortable</li>
<li>blog page: handled with markdown, filterable, sortable</li> <li>blog page: handled with markdown, filterable, sortable</li>

40
utils/draw.ts Normal file
View file

@ -0,0 +1,40 @@
import type { PointLike } from './point'
let ctx: CanvasRenderingContext2D
let screenMaxLength: number
export function initDrawVars(ctx_: CanvasRenderingContext2D, screenMaxLength_: number) {
ctx = ctx_
screenMaxLength = screenMaxLength_
}
export function drawCircle(point: PointLike) {
ctx.beginPath()
ctx.arc(point.x, point.y, 4, 0, 360)
ctx.fill()
}
export function drawLine(point0: PointLike, point1: PointLike) {
const distance = dist(point0, point1)
let transparency = 1 - (distance / (screenMaxLength))
transparency = (transparency - 0.75) * 5
if (transparency < 0)
return
ctx.lineWidth = Math.min(transparency * 2, 3)
transparency *= 255
transparency = Math.floor(transparency)
if (transparency === 0)
return
if (transparency > 255)
transparency = 255
let opacityHex = transparency.toString(16)
if (opacityHex.length === 1)
opacityHex = `0${opacityHex}`
ctx.strokeStyle = `#FFFFFF${opacityHex}`
ctx.beginPath()
ctx.moveTo(point0.x, point0.y)
ctx.lineTo(point1.x, point1.y)
ctx.stroke()
}

5
utils/math.ts Normal file
View file

@ -0,0 +1,5 @@
import type { PointLike } from './point'
export const rand = (min: number, max: number): number => Math.random() * (max - min) + min
export const mod = (num: number, val: number): number => ((num % val) + val) % val
export const dist = (point0: PointLike, point1: PointLike): number => Math.sqrt((point0.x - point1.x) ** 2 + (point0.y - point1.y) ** 2)

57
utils/point.ts Normal file
View file

@ -0,0 +1,57 @@
export class Point {
id: number
x: number
y: number
xV: number
yV: number
constructor(x?: number, y?: number) {
this.id = Point.all.length
this.x = x || rand(0, Point.maxX)
this.y = y || rand(0, Point.maxY)
this.xV = rand(-Point.maxSpeed, Point.maxSpeed)
this.yV = rand(-Point.maxSpeed, Point.maxSpeed)
Point.all.push(this)
}
step() {
this.x = mod(this.x + this.xV, Point.maxX)
this.y = mod(this.y + this.yV, Point.maxY)
}
render() {
// drawCircle(this)
// connect to other points
const leftX = -(Point.maxX - this.x)
const rightX = Point.maxX + this.x
const topY = -(Point.maxY - this.y)
const bottomY = Point.maxY + this.y
Point.all.forEach((point) => {
drawLine(point, { x: leftX, y: topY })
drawLine(point, { x: leftX, y: this.y })
drawLine(point, { x: leftX, y: bottomY })
drawLine(point, { x: this.x, y: topY })
if (point.id < this.id)
drawLine(point, this)
drawLine(point, { x: this.x, y: bottomY })
drawLine(point, { x: rightX, y: topY })
drawLine(point, { x: rightX, y: this.y })
drawLine(point, { x: rightX, y: bottomY })
})
}
static all: Point[] = []
static maxX: number
static maxY: number
static maxSpeed: number
}
export interface PointLike {
x: number
y: number
}

41
utils/pointCloud.ts Normal file
View file

@ -0,0 +1,41 @@
let width: number, height: number
let canvas: HTMLCanvasElement
let ctx: CanvasRenderingContext2D
export function handleResize() {
width = window.innerWidth
height = window.innerHeight
canvas.width = width
canvas.height = height
initPoints()
}
export function initCanvas(_canvas: HTMLCanvasElement) {
width = window.innerWidth
height = window.innerHeight
canvas = _canvas
canvas.width = width
canvas.height = height
ctx = canvas.getContext('2d')!
ctx.fillStyle = '#FFFFFF'
ctx.strokeStyle = '#FFFFFF'
initDrawVars(ctx, Math.sqrt(width ** 2 + height ** 2))
}
export function initPoints(numPoints: number = 30, maxSpeed: number = 0.25) {
Point.all = []
Point.maxX = width
Point.maxY = height
Point.maxSpeed = maxSpeed
Array.from({ length: numPoints }).forEach(() => new Point())
}
export function renderFrame() {
ctx.clearRect(0, 0, width, height)
Point.all.forEach(point => point.step())
Point.all.forEach(point => point.render())
}