get routing working, add index for poetry, list first 6 poems on index, let each take you to their page with the poem's content
This commit is contained in:
parent
2cf484aa46
commit
3d22344e7f
|
@ -0,0 +1 @@
|
||||||
|
nodejs 20.13.1
|
|
@ -12,6 +12,7 @@
|
||||||
"@threlte/core": "^7.3.0",
|
"@threlte/core": "^7.3.0",
|
||||||
"@threlte/extras": "^8.11.2",
|
"@threlte/extras": "^8.11.2",
|
||||||
"@threlte/rapier": "^2.0.0",
|
"@threlte/rapier": "^2.0.0",
|
||||||
|
"mdsvex": "^0.11.0",
|
||||||
"three": "^0.159.0",
|
"three": "^0.159.0",
|
||||||
"three-inspect": "^0.4.5"
|
"three-inspect": "^0.4.5"
|
||||||
},
|
},
|
||||||
|
@ -1986,6 +1987,11 @@
|
||||||
"meshoptimizer": "~0.18.1"
|
"meshoptimizer": "~0.18.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/unist": {
|
||||||
|
"version": "2.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz",
|
||||||
|
"integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="
|
||||||
|
},
|
||||||
"node_modules/@types/webxr": {
|
"node_modules/@types/webxr": {
|
||||||
"version": "0.5.15",
|
"version": "0.5.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.15.tgz",
|
||||||
|
@ -5028,6 +5034,20 @@
|
||||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
|
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
|
||||||
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="
|
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/mdsvex": {
|
||||||
|
"version": "0.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mdsvex/-/mdsvex-0.11.0.tgz",
|
||||||
|
"integrity": "sha512-gJF1s0N2nCmdxcKn8HDn0LKrN8poStqAicp6bBcsKFd/zkUBGLP5e7vnxu+g0pjBbDFOscUyI1mtHz+YK2TCDw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^2.0.3",
|
||||||
|
"prism-svelte": "^0.4.7",
|
||||||
|
"prismjs": "^1.17.1",
|
||||||
|
"vfile-message": "^2.0.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"svelte": ">=3 <5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/meow": {
|
"node_modules/meow": {
|
||||||
"version": "6.1.1",
|
"version": "6.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/meow/-/meow-6.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/meow/-/meow-6.1.1.tgz",
|
||||||
|
@ -5962,6 +5982,19 @@
|
||||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prism-svelte": {
|
||||||
|
"version": "0.4.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/prism-svelte/-/prism-svelte-0.4.7.tgz",
|
||||||
|
"integrity": "sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ=="
|
||||||
|
},
|
||||||
|
"node_modules/prismjs": {
|
||||||
|
"version": "1.29.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
|
||||||
|
"integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/pseudomap": {
|
"node_modules/pseudomap": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
|
||||||
|
@ -7874,6 +7907,18 @@
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/unist-util-stringify-position": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^2.0.2"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/universalify": {
|
"node_modules/universalify": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||||
|
@ -7936,6 +7981,19 @@
|
||||||
"spdx-expression-parse": "^3.0.0"
|
"spdx-expression-parse": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vfile-message": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^2.0.0",
|
||||||
|
"unist-util-stringify-position": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "5.2.10",
|
"version": "5.2.10",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.10.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.10.tgz",
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
"@threlte/core": "^7.3.0",
|
"@threlte/core": "^7.3.0",
|
||||||
"@threlte/extras": "^8.11.2",
|
"@threlte/extras": "^8.11.2",
|
||||||
"@threlte/rapier": "^2.0.0",
|
"@threlte/rapier": "^2.0.0",
|
||||||
|
"mdsvex": "^0.11.0",
|
||||||
"three": "^0.159.0",
|
"three": "^0.159.0",
|
||||||
"three-inspect": "^0.4.5"
|
"three-inspect": "^0.4.5"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { T, useTask, useThrelte } from '@threlte/core';
|
||||||
|
import { World } from '@threlte/rapier';
|
||||||
|
import { Inspector } from 'three-inspect';
|
||||||
|
import { dev } from '$app/environment';
|
||||||
|
import SpaceSkysphere from './SpaceSkysphere.svelte';
|
||||||
|
import { Group, type Object3DEventMap } from 'three';
|
||||||
|
import DollyCam from './DollyCam.svelte';
|
||||||
|
import Planet from '$lib/components/scenes/app/Planet.svelte';
|
||||||
|
|
||||||
|
const { invalidate } = useThrelte();
|
||||||
|
let spaceObjects: Group<Object3DEventMap>;
|
||||||
|
|
||||||
|
useTask(
|
||||||
|
'updateSpaceObjects',
|
||||||
|
(delta) => {
|
||||||
|
if (!spaceObjects) return;
|
||||||
|
spaceObjects.rotation.y += 0.3 * delta;
|
||||||
|
spaceObjects.position.y = Math.sin(spaceObjects.rotation.y);
|
||||||
|
|
||||||
|
invalidate();
|
||||||
|
},
|
||||||
|
{ autoInvalidate: false }
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<World gravity={[0, 0, 0]}>
|
||||||
|
<DollyCam />
|
||||||
|
|
||||||
|
<T.Group bind:ref={spaceObjects}>
|
||||||
|
<SpaceSkysphere size={100} count={500} />
|
||||||
|
|
||||||
|
<Planet />
|
||||||
|
|
||||||
|
<slot />
|
||||||
|
</T.Group>
|
||||||
|
</World>
|
||||||
|
|
||||||
|
{#if false}
|
||||||
|
<Inspector />
|
||||||
|
{/if}
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!-- src/lib/CanvasLayout.svelte -->
|
||||||
|
<script lang="ts">
|
||||||
|
import { Canvas } from '@threlte/core';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="canvas">
|
||||||
|
<Canvas>
|
||||||
|
<slot />
|
||||||
|
</Canvas>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
:global(body) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgb(0, 36, 6);
|
||||||
|
background: linear-gradient(180deg, rgba(0, 36, 6, 1) 0%, rgba(0, 0, 0, 1) 100%);
|
||||||
|
position: absolute;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,44 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { T, useTask, useThrelte } from '@threlte/core';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { PerspectiveCamera, Vector3 } from 'three';
|
||||||
|
const { invalidate } = useThrelte();
|
||||||
|
|
||||||
|
let camLookatPosition: Vector3 = new Vector3();
|
||||||
|
let camCurrentPosition: Vector3 = new Vector3();
|
||||||
|
let camDamping: number = 1;
|
||||||
|
let camera: PerspectiveCamera;
|
||||||
|
|
||||||
|
const handleMouseMove = (event: MouseEvent) => {
|
||||||
|
// normalize the mouse position to [-1, 1], and smoothly interpolate the camera's lookAt position
|
||||||
|
camLookatPosition.set(
|
||||||
|
(event.clientX / window.innerWidth) * 2 - 1,
|
||||||
|
-(event.clientY / window.innerHeight) * 2 + 1,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
useTask(
|
||||||
|
'dollyCam',
|
||||||
|
(delta) => {
|
||||||
|
if (!camera) return;
|
||||||
|
camCurrentPosition.lerp(camLookatPosition, camDamping * delta);
|
||||||
|
camera.lookAt(camCurrentPosition);
|
||||||
|
|
||||||
|
if (camera && camCurrentPosition.distanceTo(camLookatPosition) > 0.1) {
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ autoInvalidate: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
document.addEventListener('mousemove', handleMouseMove);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('mousemove', handleMouseMove);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<T.PerspectiveCamera position.z={25} makeDefault fov={50} far={10000} bind:ref={camera} />
|
|
@ -0,0 +1,51 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { HTML } from '@threlte/extras';
|
||||||
|
import { Attractor } from '@threlte/rapier';
|
||||||
|
|
||||||
|
export let position: [number, number, number] = [0, 0, 0];
|
||||||
|
export let range: number = 100;
|
||||||
|
export let clickHandler: (() => void) | undefined = undefined;
|
||||||
|
export let htmlContent: HTMLElement | string = 'Hello!';
|
||||||
|
export let href: string = '/';
|
||||||
|
|
||||||
|
let isHovering = false;
|
||||||
|
let isPointerDown = false;
|
||||||
|
|
||||||
|
const onClick = () => {
|
||||||
|
console.log('clicked!');
|
||||||
|
if (clickHandler) {
|
||||||
|
clickHandler();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<HTML position.x={position[0]} position.y={position[1]} position.z={position[2]}>
|
||||||
|
<a
|
||||||
|
{href}
|
||||||
|
on:pointerenter={() => (isHovering = true)}
|
||||||
|
on:pointerleave={() => {
|
||||||
|
isPointerDown = false;
|
||||||
|
isHovering = false;
|
||||||
|
}}
|
||||||
|
on:pointerdown={() => (isPointerDown = true)}
|
||||||
|
on:pointerup={() => (isPointerDown = false)}
|
||||||
|
on:pointercancel={() => {
|
||||||
|
isPointerDown = false;
|
||||||
|
isHovering = false;
|
||||||
|
}}
|
||||||
|
on:click={onClick}
|
||||||
|
class="bg-green-700 px-3 py-3 text-white opacity-50 hover:opacity-90 active:opacity-100"
|
||||||
|
style="transform: translate(-50%, 50%); display: block;"
|
||||||
|
>
|
||||||
|
{htmlContent}
|
||||||
|
</a>
|
||||||
|
</HTML>
|
||||||
|
|
||||||
|
<Attractor
|
||||||
|
position.x={position[0]}
|
||||||
|
position.y={position[1]}
|
||||||
|
position.z={position[2]}
|
||||||
|
{range}
|
||||||
|
strength={isHovering ? 1 : 0}
|
||||||
|
gravityType={'static'}
|
||||||
|
/>
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script lang="ts" context="module">
|
||||||
|
import { T } from '@threlte/core';
|
||||||
|
import { Attractor, Collider, RigidBody } from '@threlte/rapier';
|
||||||
|
import { MeshBasicMaterial, SphereGeometry } from 'three';
|
||||||
|
const geometry = new SphereGeometry(1, 8, 4);
|
||||||
|
const material = new MeshBasicMaterial({ color: '#339933', wireframe: true });
|
||||||
|
const position: [number, number, number] = [0, 0, 0];
|
||||||
|
const scale: number = 2;
|
||||||
|
const offset = position.map((el) => el + 1.5);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Attractor {position} range={100} strength={0.3} gravityType={'linear'} />
|
||||||
|
|
||||||
|
<T.Group position.x={-offset[0]} position.y={-offset[1]} position.z={offset[2]}>
|
||||||
|
<RigidBody linearDamping={0.3}>
|
||||||
|
<Collider shape="ball" args={[scale]} mass={scale} />
|
||||||
|
<T.Mesh scale={[scale, scale, scale]} {geometry} {material} />
|
||||||
|
</RigidBody>
|
||||||
|
</T.Group>
|
|
@ -5,7 +5,7 @@
|
||||||
import { Studio } from '@threlte/theatre';
|
import { Studio } from '@threlte/theatre';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Studio enabled={false} />
|
<Studio enabled={dev} />
|
||||||
|
|
||||||
<Canvas>
|
<Canvas>
|
||||||
<Spinners />
|
<Spinners />
|
||||||
|
|
|
@ -8,18 +8,18 @@
|
||||||
|
|
||||||
let sequence: SequenceController;
|
let sequence: SequenceController;
|
||||||
|
|
||||||
let box: Mesh;
|
let ball: Mesh;
|
||||||
let spotlight: SpotLight;
|
let spotlight: SpotLight;
|
||||||
let lastBoxPosition = new Vector3();
|
let lastBallPosition = new Vector3();
|
||||||
let currentBoxPosition = new Vector3();
|
let currentBallPosition = new Vector3();
|
||||||
let config = spinnersJson as IProjectConfig;
|
let config = spinnersJson as IProjectConfig;
|
||||||
|
|
||||||
const boxMoved: any = (props: { position: { x: number; y: number; z: number } }) => {
|
const ballMoved: any = (props: { position: { x: number; y: number; z: number } }) => {
|
||||||
if (box && spotlight) {
|
if (ball && spotlight) {
|
||||||
const { x, y, z } = props.position;
|
const { x, y, z } = props.position;
|
||||||
currentBoxPosition.set(x, y, z);
|
currentBallPosition.set(x, y, z);
|
||||||
spotlight.lookAt(currentBoxPosition);
|
spotlight.lookAt(currentBallPosition);
|
||||||
lastBoxPosition.copy(currentBoxPosition);
|
lastBallPosition.copy(currentBallPosition);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -33,10 +33,10 @@
|
||||||
<!-- create a T.SpotLight that looks at box-->
|
<!-- create a T.SpotLight that looks at box-->
|
||||||
<T.SpotLight position={[0, 5, 3]} intensity={10} bind:ref={spotlight}></T.SpotLight>
|
<T.SpotLight position={[0, 5, 3]} intensity={10} bind:ref={spotlight}></T.SpotLight>
|
||||||
|
|
||||||
<SheetObject key="Box" let:Transform let:Sync on:change={boxMoved}>
|
<SheetObject key="Box" let:Transform let:Sync on:change={ballMoved}>
|
||||||
<Transform>
|
<Transform>
|
||||||
<T.Mesh position.y={0.5} bind:ref={box}>
|
<T.Mesh position.y={0.5} bind:ref={ball}>
|
||||||
<T.BoxGeometry args={[1, 1, 1]} />
|
<T.SphereGeometry args={[1, 8, 4]} />
|
||||||
<T.MeshStandardMaterial color="#b00d03">
|
<T.MeshStandardMaterial color="#b00d03">
|
||||||
<Sync color roughness metalness />
|
<Sync color roughness metalness />
|
||||||
</T.MeshStandardMaterial>
|
</T.MeshStandardMaterial>
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import { Canvas, T } from '@threlte/core';
|
|
||||||
import { OrbitControls } from '@threlte/extras';
|
|
||||||
import OrbitingSpheres from '$lib/components/scenes/home/OrbitingSpheres.svelte';
|
|
||||||
import { World } from '@threlte/rapier';
|
|
||||||
import { Inspector } from 'three-inspect';
|
|
||||||
import { dev } from '$app/environment';
|
|
||||||
import SpaceSkysphere from './SpaceSkysphere.svelte';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<Canvas>
|
|
||||||
<World gravity={[0, 0, 0]}>
|
|
||||||
<T.PerspectiveCamera position.y={15} position.z={25} makeDefault fov={70} far={10000}>
|
|
||||||
<OrbitControls
|
|
||||||
enableZoom={false}
|
|
||||||
enablePan={false}
|
|
||||||
enableRotate={false}
|
|
||||||
enableDamping
|
|
||||||
target.y={0}
|
|
||||||
autoRotate
|
|
||||||
/>
|
|
||||||
</T.PerspectiveCamera>
|
|
||||||
|
|
||||||
<SpaceSkysphere size={100} count={500} />
|
|
||||||
|
|
||||||
<OrbitingSpheres position={[0, 0, 0]} range={10} />
|
|
||||||
</World>
|
|
||||||
|
|
||||||
{#if dev}
|
|
||||||
<Inspector />
|
|
||||||
{/if}
|
|
||||||
</Canvas>
|
|
|
@ -1,86 +0,0 @@
|
||||||
<script lang="ts" context="module">
|
|
||||||
const geometry = new SphereGeometry(1, 8, 4);
|
|
||||||
const material = new MeshBasicMaterial({ color: '#339933' });
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { T } from '@threlte/core';
|
|
||||||
import { HTML } from '@threlte/extras';
|
|
||||||
import { Attractor, Collider, RigidBody } from '@threlte/rapier';
|
|
||||||
import { MeshBasicMaterial, SphereGeometry, Vector3 } from 'three';
|
|
||||||
|
|
||||||
export let range: number = 10;
|
|
||||||
export let position: [number, number, number] = [0, 0, 0];
|
|
||||||
let isHovering = false;
|
|
||||||
let isPointerDown = false;
|
|
||||||
const bodyPositions = [
|
|
||||||
new Vector3(position[0] - range, position[0] - range, position[0] - range).toArray(),
|
|
||||||
new Vector3(position[1] + range / 2, position[1] + range, position[1] + range).toArray(),
|
|
||||||
new Vector3(position[2] + range, position[2] - range / 2, position[2] + range).toArray()
|
|
||||||
];
|
|
||||||
|
|
||||||
const getId = () => {
|
|
||||||
return Math.random().toString(16).slice(2);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getRandomSize = (): number => {
|
|
||||||
return Math.random() / 4 + 0.25;
|
|
||||||
};
|
|
||||||
|
|
||||||
const generateBodies = (c: number) => {
|
|
||||||
return Array(c)
|
|
||||||
.fill('x')
|
|
||||||
.map((_, index) => {
|
|
||||||
return {
|
|
||||||
id: getId(),
|
|
||||||
position: bodyPositions[index],
|
|
||||||
size: getRandomSize()
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onClick = () => {
|
|
||||||
console.log('clicked');
|
|
||||||
};
|
|
||||||
|
|
||||||
$: bodies = generateBodies(2);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<HTML position.x={position[0]} position.y={position[1]} position.z={position[2]}>
|
|
||||||
<button
|
|
||||||
on:pointerenter={() => (isHovering = true)}
|
|
||||||
on:pointerleave={() => {
|
|
||||||
isPointerDown = false;
|
|
||||||
isHovering = false;
|
|
||||||
}}
|
|
||||||
on:pointerdown={() => (isPointerDown = true)}
|
|
||||||
on:pointerup={() => (isPointerDown = false)}
|
|
||||||
on:pointercancel={() => {
|
|
||||||
isPointerDown = false;
|
|
||||||
isHovering = false;
|
|
||||||
}}
|
|
||||||
on:click={onClick}
|
|
||||||
class="rounded-full bg-orange-500 px-3 text-white hover:opacity-90 active:opacity-70"
|
|
||||||
>
|
|
||||||
Hello!
|
|
||||||
</button>
|
|
||||||
</HTML>
|
|
||||||
|
|
||||||
<Attractor
|
|
||||||
position.x={position[0]}
|
|
||||||
position.y={position[1]}
|
|
||||||
position.z={position[2]}
|
|
||||||
range={200}
|
|
||||||
strength={isHovering ? 1 : 0.1}
|
|
||||||
gravityType={'linear'}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{#each bodies as body (body.id)}
|
|
||||||
<T.Group position={body.position}>
|
|
||||||
<RigidBody>
|
|
||||||
<Collider shape="ball" args={[body.size]} mass={body.size} />
|
|
||||||
<Attractor range={50} strength={1} gravityType={'newtonian'} />
|
|
||||||
<T.Mesh scale={[body.size, body.size, body.size]} {geometry} {material} />
|
|
||||||
</RigidBody>
|
|
||||||
</T.Group>
|
|
||||||
{/each}
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
<script context="module">
|
||||||
|
import { tick } from 'svelte';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Usage: <div use:portal={'css selector'}> or <div use:portal={document.body}>
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} el
|
||||||
|
* @param {HTMLElement|string} target DOM Element or CSS Selector
|
||||||
|
*/
|
||||||
|
export function portal(el, target = 'body') {
|
||||||
|
let targetEl;
|
||||||
|
/**
|
||||||
|
* @param {string | HTMLElement} newTarget
|
||||||
|
*/
|
||||||
|
async function update(newTarget) {
|
||||||
|
target = newTarget;
|
||||||
|
if (typeof target === 'string') {
|
||||||
|
targetEl = document.querySelector(target);
|
||||||
|
if (targetEl === null) {
|
||||||
|
await tick();
|
||||||
|
targetEl = document.querySelector(target);
|
||||||
|
}
|
||||||
|
if (targetEl === null) {
|
||||||
|
throw new Error(`No element found matching css selector: "${target}"`);
|
||||||
|
}
|
||||||
|
} else if (target instanceof HTMLElement) {
|
||||||
|
targetEl = target;
|
||||||
|
} else {
|
||||||
|
throw new TypeError(
|
||||||
|
`Unknown portal target type: ${
|
||||||
|
target === null ? 'null' : typeof target
|
||||||
|
}. Allowed types: string (CSS selector) or HTMLElement.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
targetEl.appendChild(el);
|
||||||
|
el.hidden = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroy() {
|
||||||
|
if (el.parentNode) {
|
||||||
|
el.parentNode.removeChild(el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(target);
|
||||||
|
return {
|
||||||
|
update,
|
||||||
|
destroy
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* DOM Element or CSS Selector
|
||||||
|
* @type { HTMLElement|string}
|
||||||
|
*/
|
||||||
|
export let target = 'body';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div use:portal={target} hidden style="display: contents;">
|
||||||
|
<slot />
|
||||||
|
</div>
|
|
@ -0,0 +1,80 @@
|
||||||
|
export interface Metadata {
|
||||||
|
title: string;
|
||||||
|
date: string;
|
||||||
|
content: string;
|
||||||
|
categories?: string[];
|
||||||
|
section?: SectionKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Section {
|
||||||
|
poetry: 'poetry';
|
||||||
|
thoughts: 'thoughts';
|
||||||
|
projects: 'projects';
|
||||||
|
}
|
||||||
|
|
||||||
|
type SectionKey = keyof Section;
|
||||||
|
|
||||||
|
export interface Post {
|
||||||
|
meta: Metadata;
|
||||||
|
path: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
metadata: Metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isData(obj: unknown): obj is Data {
|
||||||
|
if (typeof obj !== 'object' || obj === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataObj = obj as Data;
|
||||||
|
|
||||||
|
return (
|
||||||
|
'metadata' in dataObj &&
|
||||||
|
typeof dataObj.metadata.title === 'string' &&
|
||||||
|
typeof dataObj.metadata.date === 'string'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const fetchMarkdownPosts = async (
|
||||||
|
section: SectionKey,
|
||||||
|
limit: number,
|
||||||
|
offset: number
|
||||||
|
): Promise<Post[]> => {
|
||||||
|
let posts: Record<string, () => Promise<unknown>>;
|
||||||
|
switch (section) {
|
||||||
|
case 'poetry':
|
||||||
|
posts = import.meta.glob('/src/posts/poetry/*.md');
|
||||||
|
break;
|
||||||
|
case 'projects':
|
||||||
|
posts = import.meta.glob('/src/routes/(app)/projects/posts/*.md');
|
||||||
|
break;
|
||||||
|
case 'thoughts':
|
||||||
|
posts = import.meta.glob('/src/routes/(app)/thoughts/posts/*.md');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error('Could not find this section');
|
||||||
|
}
|
||||||
|
const iterablePostFiles = Object.entries(posts);
|
||||||
|
|
||||||
|
const allPosts = await Promise.all(
|
||||||
|
iterablePostFiles.map(async ([path, resolver]) => {
|
||||||
|
const data = await resolver();
|
||||||
|
if (isData(data)) {
|
||||||
|
const { metadata } = data;
|
||||||
|
const postPath = path.slice(11, -3);
|
||||||
|
return {
|
||||||
|
meta: { ...metadata, section: section },
|
||||||
|
path: postPath
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
throw new Error('Could not properly parse this post');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const paginatedPosts = allPosts.slice(offset, offset + limit);
|
||||||
|
|
||||||
|
return paginatedPosts;
|
||||||
|
};
|
|
@ -0,0 +1,35 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2014-11-10 00:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Fall
|
||||||
|
title: Autumn Synesthesia
|
||||||
|
|
||||||
|
---
|
||||||
|
The trees branch out their reds and yellows.
|
||||||
|
Their last battle cry before the frost.
|
||||||
|
The further north, the more pronounced
|
||||||
|
As they recall the life they lost.
|
||||||
|
Shouting in color upon deaf ears,
|
||||||
|
Such beauty produced at a deadly cost.
|
||||||
|
|
||||||
|
The reds rage on
|
||||||
|
With blistering hate.
|
||||||
|
"Is there no escape
|
||||||
|
From our inevitable fate?"
|
||||||
|
|
||||||
|
The orange reminisce
|
||||||
|
On the seasons before.
|
||||||
|
"Winter is knocking,
|
||||||
|
But Spring is next door."
|
||||||
|
|
||||||
|
The yellows enjoy
|
||||||
|
The weather while it lasts.
|
||||||
|
"Best to live in the present
|
||||||
|
Than the future or past."
|
||||||
|
|
||||||
|
The browns mutter softly
|
||||||
|
The last lesson to learn.
|
||||||
|
"From dust I arose,
|
||||||
|
So to dust I return."
|
|
@ -0,0 +1,31 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2014-05-20 00:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Humor
|
||||||
|
- Muffins
|
||||||
|
- Love
|
||||||
|
- Relationships
|
||||||
|
title: Breakfast Blue Pt. 2
|
||||||
|
|
||||||
|
---
|
||||||
|
Oh, my good friend, I didn't mean to leave.
|
||||||
|
It wasn't your fault, so no longer grieve!
|
||||||
|
If I could, I would run back to your side.
|
||||||
|
But, alas, a lack of legs slows my stride.
|
||||||
|
|
||||||
|
It's been over a year since I've last seen
|
||||||
|
Your serious face and Chartwell's cuisine.
|
||||||
|
Often I think this is for the better
|
||||||
|
\'Til I shed tears as I read your letter.
|
||||||
|
|
||||||
|
Fake tears, that is, for I also lack eyes.
|
||||||
|
In fact, let me unveil my disguise:
|
||||||
|
I'm an object lacking animation,
|
||||||
|
Given life through personification.
|
||||||
|
|
||||||
|
What words can I say to help you move on
|
||||||
|
And accept the fact that I am now gone?
|
||||||
|
Know that I too will miss your sweet lovin'
|
||||||
|
For I'll always be your chocolate muffin.
|
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2013-01-10 00:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Humor
|
||||||
|
- Muffins
|
||||||
|
title: Breakfast Blues
|
||||||
|
|
||||||
|
---
|
||||||
|
Lost my reason to wake in the morning
|
||||||
|
Ever since you left me without warning.
|
||||||
|
We've always seemed to have gotten along
|
||||||
|
Now I'm wondering if I did you wrong.
|
||||||
|
|
||||||
|
Lost my reason to give you thanks and praise.
|
||||||
|
Each day that passes passes in a daze.
|
||||||
|
The life I live is a life of decay.
|
||||||
|
My happiness happens to never stay.
|
||||||
|
|
||||||
|
I would have treated you so much better,
|
||||||
|
Or perhaps branded a scarlet letter
|
||||||
|
Across my chest and openly confess
|
||||||
|
That I'm impressed by a snack I love best.
|
||||||
|
|
||||||
|
Oh chocolate muffin, why'd you have to leave?
|
||||||
|
I've learned not to wear my heart on my sleeve.
|
||||||
|
Instead my love will always be suppressed
|
||||||
|
As I keep it locked in a chocolate chest.
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2019-03-06 12:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Christian
|
||||||
|
title: Djinn
|
||||||
|
year: 2019
|
||||||
|
---
|
||||||
|
|
||||||
|
"Jesus dropped by."
|
||||||
|
My roommate remarked.
|
||||||
|
"He told me to tell you
|
||||||
|
His phone fell apart."
|
||||||
|
|
||||||
|
I let out a chuckle
|
||||||
|
And a sigh of relief.
|
||||||
|
"He didn't holy ghost us
|
||||||
|
Despite such unbelief."
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2018-04-28 12:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Wisdom
|
||||||
|
- Lessons
|
||||||
|
title: I've Seen
|
||||||
|
year: 2018
|
||||||
|
|
||||||
|
---
|
||||||
|
I've seen tears fall
|
||||||
|
From the face of a giant,
|
||||||
|
A hint of desperation
|
||||||
|
In the pleas of a king,
|
||||||
|
|
||||||
|
An attempt to forgive
|
||||||
|
The guilt-tripping violent,
|
||||||
|
Their genuine surprise
|
||||||
|
That neither learned a thing.
|
||||||
|
|
||||||
|
The wishes of a mother
|
||||||
|
Remain whispers in the wind,
|
||||||
|
And the riches of the world
|
||||||
|
In the words of humbled men.
|
|
@ -0,0 +1,43 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2019-02-02 12:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Love
|
||||||
|
- Lovers
|
||||||
|
- Relationships
|
||||||
|
- Introspective
|
||||||
|
title: Infrared Homing
|
||||||
|
---
|
||||||
|
|
||||||
|
In a moment
|
||||||
|
Of relapse,
|
||||||
|
A desire
|
||||||
|
For love
|
||||||
|
Arose.
|
||||||
|
|
||||||
|
I gave my heartstrings
|
||||||
|
To a girl
|
||||||
|
To knit a warmer
|
||||||
|
Set of clothes.
|
||||||
|
|
||||||
|
I was hoping
|
||||||
|
For a sweater,
|
||||||
|
But instead,
|
||||||
|
Received her mask.
|
||||||
|
|
||||||
|
She thanked me kindly
|
||||||
|
For the coat
|
||||||
|
And I knew
|
||||||
|
I shouldn't ask.
|
||||||
|
|
||||||
|
Was it
|
||||||
|
Seasonal depression
|
||||||
|
That left me seeking
|
||||||
|
Out a sun?
|
||||||
|
|
||||||
|
A candle
|
||||||
|
Can't replace it,
|
||||||
|
But any fire
|
||||||
|
Is better than none.
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2020-10-01 20:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Neuroscience
|
||||||
|
- Wisdom
|
||||||
|
title: Judge Judy
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
With each passing moment,
|
||||||
|
A court case is held
|
||||||
|
For our mind to determine
|
||||||
|
Which actions to compel.
|
||||||
|
|
||||||
|
86 billion neurons
|
||||||
|
Take up the jury seats
|
||||||
|
And fire off responses
|
||||||
|
'Til a majority agrees.
|
||||||
|
|
||||||
|
"Your Honor, you don't exist,
|
||||||
|
But as an emergent behavior;
|
||||||
|
Yet still we reached a verdict
|
||||||
|
That should work in our favor."
|
||||||
|
|
||||||
|
The neurons are dismissed
|
||||||
|
Then return to jury duty
|
||||||
|
For another microcosm case
|
||||||
|
In their show of Judge Judy.
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2018-06-25 20:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Chess
|
||||||
|
- Lessons
|
||||||
|
title: King's Pin
|
||||||
|
year: 2018
|
||||||
|
---
|
||||||
|
|
||||||
|
You placed my king
|
||||||
|
In a surprising check
|
||||||
|
To ensure I’m kept
|
||||||
|
On the tip of my toes.
|
||||||
|
|
||||||
|
Only a few
|
||||||
|
Of our pieces are left,
|
||||||
|
And each one of my moves
|
||||||
|
Are presupposed.
|
||||||
|
|
||||||
|
Unbeknownst,
|
||||||
|
Synonymous to beginner.
|
||||||
|
|
||||||
|
A satisfying poach
|
||||||
|
Awarded to the winner.
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2014-10-27 00:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Humor
|
||||||
|
title: Klepto Couches
|
||||||
|
|
||||||
|
---
|
||||||
|
My home houses countless couches.
|
||||||
|
Klepto-couches with pickpocket pouches
|
||||||
|
That swiftly swipe your cellular phone
|
||||||
|
Between the cushions of their comfy unknown.
|
||||||
|
|
||||||
|
Then your change jingles and jangles
|
||||||
|
Until they're untangled
|
||||||
|
From your Wrangler jeans pocket
|
||||||
|
As you wonder where your socks went.
|
||||||
|
|
||||||
|
But your socks and shoes
|
||||||
|
Were swept under your feet
|
||||||
|
Right under your nose.
|
||||||
|
|
||||||
|
So discreet are these deceitful seats
|
||||||
|
As they watch you search
|
||||||
|
For the keys they stole.
|
||||||
|
|
||||||
|
At last your quest
|
||||||
|
Leads you straight to the crook.
|
||||||
|
"I should have guessed
|
||||||
|
The klepto-couches had took!"
|
||||||
|
|
||||||
|
But still your lesson
|
||||||
|
Has yet to be learned.
|
||||||
|
These klepto-couches
|
||||||
|
Deserve to be burned.
|
|
@ -0,0 +1,33 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2012-02-25 00:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Grounds
|
||||||
|
- Covenant
|
||||||
|
title: Leafblower
|
||||||
|
|
||||||
|
---
|
||||||
|
You're the girl sitting on the park bench.
|
||||||
|
I'm the guy with a leaf blower.
|
||||||
|
I've gotta do my job,
|
||||||
|
So would you kindly please move over?
|
||||||
|
|
||||||
|
I'm walking right towards you,
|
||||||
|
So don't say you didn't notice me.
|
||||||
|
I'd like to get off work soon,
|
||||||
|
So I'll give you until the count of three.
|
||||||
|
|
||||||
|
One
|
||||||
|
Two
|
||||||
|
...
|
||||||
|
|
||||||
|
Alright, so you've called my bluff.
|
||||||
|
I'm not really going to do anything.
|
||||||
|
I just wanted to look real tough,
|
||||||
|
But this little bee ain't got no sting.
|
||||||
|
|
||||||
|
I'll just tell my boss that I missed a spot,
|
||||||
|
And I'll explain my sad situation.
|
||||||
|
Then we'll both laugh at the thought
|
||||||
|
Of me writing poetry about my frustration.
|
|
@ -0,0 +1,52 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2019-10-26 12:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Wisdom
|
||||||
|
title: Of Molecules And Men
|
||||||
|
---
|
||||||
|
|
||||||
|
May we lose
|
||||||
|
All language
|
||||||
|
That we may see
|
||||||
|
As it is
|
||||||
|
And not
|
||||||
|
As we think,
|
||||||
|
|
||||||
|
For cells
|
||||||
|
Arose
|
||||||
|
From division
|
||||||
|
To divide
|
||||||
|
And conquer
|
||||||
|
Molecules
|
||||||
|
And men.
|
||||||
|
|
||||||
|
From the
|
||||||
|
Prokaryote
|
||||||
|
To the
|
||||||
|
Proletariat
|
||||||
|
A conflict
|
||||||
|
Ensues.
|
||||||
|
|
||||||
|
You're so sure
|
||||||
|
That you're full
|
||||||
|
Of yourself
|
||||||
|
As your cells
|
||||||
|
Dismantle
|
||||||
|
All that's
|
||||||
|
Consumed.
|
||||||
|
|
||||||
|
We break to build
|
||||||
|
Each building block
|
||||||
|
Into a likeness
|
||||||
|
Worth worshipping to.
|
||||||
|
|
||||||
|
To be at peace
|
||||||
|
Is to decompose.
|
||||||
|
|
||||||
|
To cease to be
|
||||||
|
Is to become
|
||||||
|
Every friend
|
||||||
|
And alleged foe.
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2012-03-01 00:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Grounds
|
||||||
|
- Covenant
|
||||||
|
title: Monday Morning Shift
|
||||||
|
|
||||||
|
---
|
||||||
|
These plants look beautiful, but not at this location.
|
||||||
|
They must be eradicated according to administration.
|
||||||
|
I brought out my tools; Some gloves and a spade,
|
||||||
|
Then sat down, Indian style, to begin the raid.
|
||||||
|
The roots, like little fingers, held on to dear life
|
||||||
|
As I cut through their homes with an oddly-shaped knife.
|
||||||
|
|
||||||
|
To justify these cruel killings
|
||||||
|
I thought of what they've done:
|
||||||
|
Suffocated the superior plants
|
||||||
|
And blocked out the lovely sun.
|
||||||
|
|
||||||
|
But what makes one plant superior and the other inferior?
|
||||||
|
Just the fact that the other has a beautiful exterior?
|
||||||
|
They are simply trying their best to make a living.
|
||||||
|
We must see past our differences and be more forgiving.
|
||||||
|
|
||||||
|
But these thoughts lead down to a dangerous road;
|
||||||
|
Let's not personify each seed we've sowed.
|
||||||
|
|
||||||
|
The sun now rises and heats the ground.
|
||||||
|
The ice embedded within melts all around,
|
||||||
|
And now a nice wet spot on my pants is found
|
||||||
|
Which leaves me thinking of thoughts more profound:
|
||||||
|
"I really hope no one's looking at me right now."
|
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2016-05-10 00:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Work
|
||||||
|
- Worry
|
||||||
|
- Self-conscious
|
||||||
|
title: Morning Commute
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
A few minutes into my morning commute
|
||||||
|
I had forgotten we can all read minds.
|
||||||
|
So my thought faucet ran up my brain bill
|
||||||
|
Spewing a membraneous mess inside.
|
||||||
|
|
||||||
|
I didn’t notice ‘til I parked the car
|
||||||
|
And smelled the fumes from under the hood.
|
||||||
|
I frantically thought of cats and cookies
|
||||||
|
To clean up the mess, but it did no good.
|
||||||
|
|
||||||
|
So I ditched the car and snuck into work,
|
||||||
|
Though I knew my hopes and dreams would be seen
|
||||||
|
Swirled amidst my self-doubt and worries
|
||||||
|
Like creamer mixed in bitter cups of caffeine.
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2015-07-15 00:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Relationships
|
||||||
|
- Love
|
||||||
|
- Drinking
|
||||||
|
- Humor
|
||||||
|
title: Perfect Situation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
When I'm hammered,
|
||||||
|
I'm left enamored
|
||||||
|
And content
|
||||||
|
With the Fate
|
||||||
|
Lady luck's prescribed.
|
||||||
|
|
||||||
|
Though we never
|
||||||
|
Will land together,
|
||||||
|
We're fledglings
|
||||||
|
With new wings
|
||||||
|
To take to the sky.
|
||||||
|
|
||||||
|
I ponder your passion
|
||||||
|
To pursue aspirations
|
||||||
|
And wonder what magic
|
||||||
|
You'll perform upon nations
|
||||||
|
|
||||||
|
And I speculate the odds
|
||||||
|
Given a perfect situation
|
||||||
|
In a parallel universe
|
||||||
|
If I'd rise to the occasion.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2016-12-20 00:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Introspective
|
||||||
|
- Silence
|
||||||
|
title: Silent Silas
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The windows to my soul
|
||||||
|
Tend to have their blinds up,
|
||||||
|
And I leave the door locked tight
|
||||||
|
By keeping my own mouth shut
|
||||||
|
|
||||||
|
So my apologies if it's frustrating
|
||||||
|
That I'm so cold and calculating.
|
||||||
|
|
||||||
|
It's my modus operandi;
|
||||||
|
You can't spell "Silent" without Si.
|
||||||
|
|
||||||
|
But if it's any consolation,
|
||||||
|
I am striving to get better
|
||||||
|
At voicing my own thoughts
|
||||||
|
Without resorting to writing letters.
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2014-07-20 00:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Love
|
||||||
|
- Relationships
|
||||||
|
- Realtalk
|
||||||
|
title: Thought Experiment
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Love is a free fall
|
||||||
|
And I'm afraid of the ground.
|
||||||
|
If I jump and no one's there,
|
||||||
|
Will my body make a sound?
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2017-10-10 00:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Wisdom
|
||||||
|
- Speech
|
||||||
|
- Verbal Abuse
|
||||||
|
title: Unintentional Internalization
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Our skin's as thick
|
||||||
|
As our words are sharp
|
||||||
|
To dampen the damage
|
||||||
|
We take to heart.
|
||||||
|
|
||||||
|
But sometimes they pierce
|
||||||
|
Right through our defenses,
|
||||||
|
Despite whether the offender
|
||||||
|
Had the best of intentions.
|
||||||
|
|
||||||
|
It's a wound that lingers
|
||||||
|
And leads to a scar
|
||||||
|
Once committed to memory
|
||||||
|
(Which shapes who you are).
|
||||||
|
|
||||||
|
For each one we've endured,
|
||||||
|
We've dealt so many more
|
||||||
|
For the most innocuous remark
|
||||||
|
Still can pierce like a sword.
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Poetry
|
||||||
|
date: 2013-05-10 00:00:00 +0000
|
||||||
|
tags:
|
||||||
|
- Realtalk
|
||||||
|
title: Who Am I?
|
||||||
|
|
||||||
|
---
|
||||||
|
Am I the clothes on my back
|
||||||
|
And the hair on my head?
|
||||||
|
Am I the people I'm with
|
||||||
|
And the words I've said?
|
||||||
|
|
||||||
|
Am I the field I study
|
||||||
|
And the school I attend?
|
||||||
|
Am I the programs I write
|
||||||
|
And the poems I've penned?
|
||||||
|
|
||||||
|
Am I the music I enjoy
|
||||||
|
And the guitar I play?
|
||||||
|
Am I the grade on my test
|
||||||
|
And my ten page essay?
|
||||||
|
|
||||||
|
Am I the habits I've formed
|
||||||
|
And the phrases I repeat?
|
||||||
|
Am I the fake smile given
|
||||||
|
To every person I meet?
|
||||||
|
|
||||||
|
Am I the religion I follow
|
||||||
|
And the politician I elect?
|
||||||
|
Am I every action I carry out
|
||||||
|
And every thought I reflect?
|
|
@ -0,0 +1,7 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import App from '$lib/components/scenes/app/App.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<App>
|
||||||
|
<slot />
|
||||||
|
</App>
|
|
@ -0,0 +1,23 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import MenuItem from '$lib/components/scenes/app/MenuItem.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<MenuItem position={[-2.5, 7.5, 0]} htmlContent="Poetry" href="/poetry" />
|
||||||
|
|
||||||
|
<MenuItem
|
||||||
|
position={[2.5, 2.5, -2.5]}
|
||||||
|
htmlContent="Projects"
|
||||||
|
clickHandler={() => console.log('clicked!')}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MenuItem
|
||||||
|
position={[-2.5, -2.5, -2.5]}
|
||||||
|
htmlContent="Thoughts"
|
||||||
|
clickHandler={() => console.log('clicked!')}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MenuItem
|
||||||
|
position={[2.5, -7.5, 2.5]}
|
||||||
|
htmlContent="About"
|
||||||
|
clickHandler={() => console.log('clicked!')}
|
||||||
|
/>
|
|
@ -0,0 +1,39 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import MenuItem from '$lib/components/scenes/app/MenuItem.svelte';
|
||||||
|
import type { PageData } from './$types';
|
||||||
|
export let data: PageData;
|
||||||
|
|
||||||
|
const xMin = -2.5,
|
||||||
|
xMax = 2.5;
|
||||||
|
const yMin = -7.5,
|
||||||
|
yMax = 7.5;
|
||||||
|
const zMin = -2.5,
|
||||||
|
zMax = 2.5;
|
||||||
|
|
||||||
|
// Calculate positions
|
||||||
|
const calculatePositions = (numPosts: number): Array<[number, number, number]> => {
|
||||||
|
const positions: Array<[number, number, number]> = [];
|
||||||
|
const numRows = Math.ceil(Math.sqrt(numPosts));
|
||||||
|
const numCols = Math.ceil(numPosts / numRows);
|
||||||
|
|
||||||
|
for (let i = 0; i < numPosts; i++) {
|
||||||
|
const row = Math.floor(i / numCols);
|
||||||
|
const col = i % numCols;
|
||||||
|
|
||||||
|
const x = xMin + (xMax - xMin) * (col / (numCols - 1));
|
||||||
|
const y = yMin + (yMax - yMin) * (row / (numRows - 1));
|
||||||
|
const z = zMin;
|
||||||
|
|
||||||
|
positions.push([x, y, z]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return positions;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate positions based on the number of posts
|
||||||
|
const positions = calculatePositions(data.posts.length);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#each data.posts as post, i}
|
||||||
|
<MenuItem position={positions[i]} htmlContent={post.meta.title} href={post.path} />
|
||||||
|
{/each}
|
|
@ -0,0 +1,8 @@
|
||||||
|
export const load = async ({ fetch }) => {
|
||||||
|
const response = await fetch(`/api/poetry?limit=5&offset=0`);
|
||||||
|
const posts = await response.json();
|
||||||
|
|
||||||
|
return {
|
||||||
|
posts
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import MenuItem from '$lib/components/scenes/app/MenuItem.svelte';
|
||||||
|
import type { PageData } from './$types';
|
||||||
|
import DomPortal from '$lib/utils/DomPortal.svelte';
|
||||||
|
export let data: PageData;
|
||||||
|
|
||||||
|
const { title, date: _date, Content, categories: _ } = data;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<MenuItem position={[-2.5, 10, 0]} htmlContent="Back" href="/poetry" />
|
||||||
|
|
||||||
|
<DomPortal target="#overlay">
|
||||||
|
<div class="py-4">
|
||||||
|
<h1 class="text-xl font-medium text-black pb-2">{title}</h1>
|
||||||
|
<div>
|
||||||
|
<Content />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DomPortal>
|
|
@ -0,0 +1,18 @@
|
||||||
|
import type { Metadata } from '$lib/utils/index.js';
|
||||||
|
|
||||||
|
export async function load({ params }) {
|
||||||
|
const post = await import(`../../../../posts/poetry/${params.slug}.md`);
|
||||||
|
const { title, date, categories } = post.metadata as Metadata;
|
||||||
|
const Content = post.default;
|
||||||
|
const parsedDate = new Date(date.slice(0, date.length - 6));
|
||||||
|
const validDate = `${
|
||||||
|
parsedDate.getMonth() + 1
|
||||||
|
}/${parsedDate.getDate()}/${parsedDate.getFullYear()}`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
Content,
|
||||||
|
title,
|
||||||
|
date: validDate,
|
||||||
|
categories
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,5 +1,38 @@
|
||||||
<script>
|
<script lang="ts">
|
||||||
import "../app.css";
|
import CanvasContainer from '$lib/components/scenes/app/CanvasContainer.svelte';
|
||||||
|
import '../app.css';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<slot />
|
<CanvasContainer>
|
||||||
|
<slot />
|
||||||
|
</CanvasContainer>
|
||||||
|
|
||||||
|
<div class="overlay container" id="overlay"></div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
:global(body) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgb(0, 36, 6);
|
||||||
|
background: linear-gradient(180deg, rgba(0, 36, 6, 1) 0%, rgba(0, 0, 0, 1) 100%);
|
||||||
|
position: absolute;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background: rgba(16, 56, 30, 0.9);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import Home from '$lib/components/scenes/home/Home.svelte';
|
|
||||||
import type { PageData } from './$types';
|
|
||||||
export let data: PageData;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
{#each data.models as model}
|
|
||||||
<span>{model.title}</span>
|
|
||||||
{/each}
|
|
||||||
<Home />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
:global(body) {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div {
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
background: rgb(0, 36, 6);
|
|
||||||
background: linear-gradient(180deg, rgba(0, 36, 6, 1) 0%, rgba(0, 0, 0, 1) 100%);
|
|
||||||
display: absolute;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,15 +0,0 @@
|
||||||
const models: Model[] = [
|
|
||||||
{ title: 'Model 1' },
|
|
||||||
{ title: 'Model 2' },
|
|
||||||
{ title: 'Model 3' }
|
|
||||||
];
|
|
||||||
|
|
||||||
export type Model = { title: string}
|
|
||||||
|
|
||||||
export function load(): { models: Model[] } {
|
|
||||||
return {
|
|
||||||
models: models.map((model) => ({
|
|
||||||
title: model.title
|
|
||||||
}))
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { fetchMarkdownPosts } from '$lib/utils';
|
||||||
|
import { json } from '@sveltejs/kit';
|
||||||
|
|
||||||
|
export const GET = async ({ url }) => {
|
||||||
|
const limit = Number(url.searchParams.get('limit')) || 6;
|
||||||
|
const offset = Number(url.searchParams.get('offset')) || 0;
|
||||||
|
const allPosts = await fetchMarkdownPosts('poetry', limit, offset);
|
||||||
|
|
||||||
|
const sortedPosts = allPosts.sort((a, b) => {
|
||||||
|
return new Date(b.meta.date).getTime() - new Date(a.meta.date).getTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
return json(sortedPosts);
|
||||||
|
};
|
|
@ -1,18 +1,20 @@
|
||||||
import adapter from '@sveltejs/adapter-auto';
|
import adapter from '@sveltejs/adapter-auto';
|
||||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||||
|
import { mdsvex } from 'mdsvex';
|
||||||
|
|
||||||
/** @type {import('@sveltejs/kit').Config} */
|
/** @type {import('@sveltejs/kit').Config} */
|
||||||
const config = {
|
const config = {
|
||||||
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
||||||
// for more information about preprocessors
|
// for more information about preprocessors
|
||||||
preprocess: vitePreprocess(),
|
preprocess: [vitePreprocess(), mdsvex({ extensions: ['.md'] })],
|
||||||
|
|
||||||
kit: {
|
kit: {
|
||||||
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
||||||
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
||||||
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
||||||
adapter: adapter()
|
adapter: adapter()
|
||||||
}
|
},
|
||||||
|
extensions: ['.svelte', '.md']
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|
Loading…
Reference in New Issue