mirror of
https://github.com/CodeF53/personal-site.git
synced 2024-09-20 06:10:34 +00:00
background
This commit is contained in:
parent
675354d7c4
commit
d482c3a0ea
12 changed files with 228 additions and 3 deletions
10
.vscode/settings.json
vendored
10
.vscode/settings.json
vendored
|
@ -35,5 +35,13 @@
|
||||||
"json",
|
"json",
|
||||||
"jsonc",
|
"jsonc",
|
||||||
"yaml"
|
"yaml"
|
||||||
]
|
],
|
||||||
|
|
||||||
|
// volar as formatter
|
||||||
|
"[vue]": {
|
||||||
|
"editor.defaultFormatter": "Vue.volar"
|
||||||
|
},
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.defaultFormatter": "Vue.volar"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
1
app.vue
1
app.vue
|
@ -1,4 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
|
<Background />
|
||||||
<NuxtLayout>
|
<NuxtLayout>
|
||||||
<NuxtPage />
|
<NuxtPage />
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
|
|
|
@ -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
34
components/Background.vue
Normal 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>
|
|
@ -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
33
package-lock.json
generated
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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
40
utils/draw.ts
Normal 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
5
utils/math.ts
Normal 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
57
utils/point.ts
Normal 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
41
utils/pointCloud.ts
Normal 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())
|
||||||
|
}
|
Loading…
Reference in a new issue