new portfolio yay!
This commit is contained in:
parent
88bd40c942
commit
786c414eb3
3
.eslintrc.json
Normal file
3
.eslintrc.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "next/core-web-vitals"
|
||||
}
|
45
.gitignore
vendored
45
.gitignore
vendored
@ -1,21 +1,36 @@
|
||||
node_modules
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# Output
|
||||
.output
|
||||
.vercel
|
||||
/.svelte-kit
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
.yarn/install-state.gz
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# OS
|
||||
# misc
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
*.pem
|
||||
|
||||
# Env
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.test
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Vite
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
@ -1,4 +0,0 @@
|
||||
# Package Managers
|
||||
package-lock.json
|
||||
pnpm-lock.yaml
|
||||
yarn.lock
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"useTabs": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 100,
|
||||
"plugins": ["prettier-plugin-svelte"],
|
||||
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
||||
}
|
52
README.md
52
README.md
@ -1,38 +1,36 @@
|
||||
# create-svelte
|
||||
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
||||
|
||||
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
|
||||
## Getting Started
|
||||
|
||||
## Creating a project
|
||||
|
||||
If you're seeing this, you've probably already done this step. Congrats!
|
||||
|
||||
```bash
|
||||
# create a new project in the current directory
|
||||
npm create svelte@latest
|
||||
|
||||
# create a new project in my-app
|
||||
npm create svelte@latest my-app
|
||||
```
|
||||
|
||||
## Developing
|
||||
|
||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
|
||||
# or start the server and open the app in a new browser tab
|
||||
npm run dev -- --open
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun dev
|
||||
```
|
||||
|
||||
## Building
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
To create a production version of your app:
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
|
||||
|
||||
You can preview the production build with `npm run preview`.
|
||||
## Learn More
|
||||
|
||||
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
||||
|
@ -1,33 +0,0 @@
|
||||
import js from '@eslint/js';
|
||||
import ts from 'typescript-eslint';
|
||||
import svelte from 'eslint-plugin-svelte';
|
||||
import prettier from 'eslint-config-prettier';
|
||||
import globals from 'globals';
|
||||
|
||||
/** @type {import('eslint').Linter.FlatConfig[]} */
|
||||
export default [
|
||||
js.configs.recommended,
|
||||
...ts.configs.recommended,
|
||||
...svelte.configs['flat/recommended'],
|
||||
prettier,
|
||||
...svelte.configs['flat/prettier'],
|
||||
{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.node
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.svelte'],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
parser: ts.parser
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
ignores: ['build/', '.svelte-kit/', 'dist/']
|
||||
}
|
||||
];
|
4
next.config.mjs
Normal file
4
next.config.mjs
Normal file
@ -0,0 +1,4 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
|
||||
export default nextConfig;
|
5574
package-lock.json
generated
Normal file
5574
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
57
package.json
57
package.json
@ -1,40 +1,31 @@
|
||||
{
|
||||
"name": "portfolio",
|
||||
"version": "0.0.1",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"lint": "prettier --check . && eslint .",
|
||||
"format": "prettier --write .",
|
||||
"model-pipeline:run": "node scripts/model-pipeline.js"
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-three/drei": "^9.108.4",
|
||||
"@react-three/fiber": "^8.16.8",
|
||||
"@types/three": "^0.166.0",
|
||||
"next": "14.2.5",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"three": "^0.166.1",
|
||||
"three-stdlib": "^2.30.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^3.0.0",
|
||||
"@sveltejs/kit": "^2.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||
"@types/eslint": "^8.56.7",
|
||||
"eslint": "^9.0.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-svelte": "^2.36.0",
|
||||
"globals": "^15.0.0",
|
||||
"prettier": "^3.1.1",
|
||||
"prettier-plugin-svelte": "^3.1.2",
|
||||
"svelte": "^4.2.7",
|
||||
"svelte-check": "^3.6.0",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^5.0.0",
|
||||
"typescript-eslint": "^8.0.0-alpha.20",
|
||||
"vite": "^5.0.3",
|
||||
"@types/three": "^0.159.0"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"three": "^0.159.0",
|
||||
"@threlte/core": "^7.3.1",
|
||||
"@threlte/extras": "^8.11.4"
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "14.2.5",
|
||||
"postcss": "^8",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
8
postcss.config.mjs
Normal file
8
postcss.config.mjs
Normal file
@ -0,0 +1,8 @@
|
||||
/** @type {import('postcss-load-config').Config} */
|
||||
const config = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
BIN
public/bootup.mp3
Normal file
BIN
public/bootup.mp3
Normal file
Binary file not shown.
BIN
public/enter.mp3
Normal file
BIN
public/enter.mp3
Normal file
Binary file not shown.
BIN
public/key.mp3
Normal file
BIN
public/key.mp3
Normal file
Binary file not shown.
BIN
public/shrimp_smol.glb
Normal file
BIN
public/shrimp_smol.glb
Normal file
Binary file not shown.
BIN
public/welcome.mp3
Normal file
BIN
public/welcome.mp3
Normal file
Binary file not shown.
@ -1,149 +0,0 @@
|
||||
import { execSync } from 'node:child_process'
|
||||
import { readdirSync, copyFileSync, unlinkSync, mkdirSync, existsSync } from 'node:fs'
|
||||
import { join, resolve } from 'node:path'
|
||||
import { exit } from 'node:process'
|
||||
|
||||
/**
|
||||
* This script is used to transform gltf and glb files into Threlte components.
|
||||
* It uses the `@threlte/gltf` package to do so.
|
||||
* It works in two steps:
|
||||
* 1. Transform the gltf/glb files located in the sourceDir directory
|
||||
* 2. Move the Threlte components to the targetDir directory
|
||||
*/
|
||||
const configuration = {
|
||||
sourceDir: resolve(join('static', 'models')),
|
||||
targetDir: resolve(join('src', 'lib', 'components', 'models')),
|
||||
overwrite: false,
|
||||
root: '/models/',
|
||||
types: true,
|
||||
keepnames: false,
|
||||
meta: false,
|
||||
shadows: false,
|
||||
printwidth: 120,
|
||||
precision: 2,
|
||||
draco: null,
|
||||
preload: false,
|
||||
suspense: false,
|
||||
isolated: false,
|
||||
transform: {
|
||||
enabled: false,
|
||||
resolution: 1024,
|
||||
simplify: {
|
||||
enabled: false,
|
||||
weld: 0.0001,
|
||||
ratio: 0.75,
|
||||
error: 0.001
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the target directory doesn't exist, create it
|
||||
mkdirSync(configuration.targetDir, { recursive: true })
|
||||
|
||||
// throw error if source directory doesn't exist
|
||||
if (!existsSync(configuration.sourceDir)) {
|
||||
throw new Error(`Source directory ${configuration.sourceDir} doesn't exist.`)
|
||||
}
|
||||
|
||||
// read the directory, filter for .glb and .gltf files and files *not* ending
|
||||
// with -transformed.gltf or -transformed.glb as these should not be transformed
|
||||
// again.
|
||||
const gltfFiles = readdirSync(configuration.sourceDir).filter((file) => {
|
||||
return (
|
||||
(file.endsWith('.glb') || file.endsWith('.gltf')) &&
|
||||
!file.endsWith('-transformed.gltf') &&
|
||||
!file.endsWith('-transformed.glb')
|
||||
)
|
||||
})
|
||||
|
||||
if (gltfFiles.length === 0) {
|
||||
console.log('No gltf or glb files found.')
|
||||
exit()
|
||||
}
|
||||
|
||||
const filteredGltfFiles = gltfFiles.filter((file) => {
|
||||
if (!configuration.overwrite) {
|
||||
const componentFilename = file.split('.').slice(0, -1).join('.') + '.svelte'
|
||||
const componentPath = join(configuration.targetDir, componentFilename)
|
||||
if (existsSync(componentPath)) {
|
||||
console.error(`File ${componentPath} already exists, skipping.`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
if (filteredGltfFiles.length === 0) {
|
||||
console.log('No gltf or glb files to process.')
|
||||
exit()
|
||||
}
|
||||
|
||||
filteredGltfFiles.forEach((file) => {
|
||||
// run the gltf transform command on every file
|
||||
const path = join(configuration.sourceDir, file)
|
||||
|
||||
// parse the configuration
|
||||
const args = []
|
||||
if (configuration.root) args.push(`--root ${configuration.root}`)
|
||||
if (configuration.types) args.push('--types')
|
||||
if (configuration.keepnames) args.push('--keepnames')
|
||||
if (configuration.meta) args.push('--meta')
|
||||
if (configuration.shadows) args.push('--shadows')
|
||||
args.push(`--printwidth ${configuration.printwidth}`)
|
||||
args.push(`--precision ${configuration.precision}`)
|
||||
if (configuration.draco) args.push(`--draco ${configuration.draco}`)
|
||||
if (configuration.preload) args.push('--preload')
|
||||
if (configuration.suspense) args.push('--suspense')
|
||||
if (configuration.isolated) args.push('--isolated')
|
||||
if (configuration.transform.enabled) {
|
||||
args.push(`--transform`)
|
||||
args.push(`--resolution ${configuration.transform.resolution}`)
|
||||
if (configuration.transform.simplify.enabled) {
|
||||
args.push(`--simplify`)
|
||||
args.push(`--weld ${configuration.transform.simplify.weld}`)
|
||||
args.push(`--ratio ${configuration.transform.simplify.ratio}`)
|
||||
args.push(`--error ${configuration.transform.simplify.error}`)
|
||||
}
|
||||
}
|
||||
const formattedArgs = args.join(' ')
|
||||
|
||||
// run the command
|
||||
const cmd = `npx @threlte/gltf@latest ${path} ${formattedArgs}`
|
||||
try {
|
||||
execSync(cmd, {
|
||||
cwd: configuration.sourceDir
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(`Error transforming model: ${error}`)
|
||||
}
|
||||
})
|
||||
|
||||
// read dir again, but search for .svelte files only.
|
||||
const svelteFiles = readdirSync(configuration.sourceDir).filter((file) => file.endsWith('.svelte'))
|
||||
|
||||
svelteFiles.forEach((file) => {
|
||||
// now move every file to /src/components/models
|
||||
const path = join(configuration.sourceDir, file)
|
||||
const newPath = join(configuration.targetDir, file)
|
||||
copyFile: try {
|
||||
// Sanity check, we checked earlier if the file exists. Still, the CLI takes
|
||||
// a while, so who knows what happens in the meantime.
|
||||
if (!configuration.overwrite) {
|
||||
// check if file already exists
|
||||
if (existsSync(newPath)) {
|
||||
console.error(`File ${newPath} already exists, skipping.`)
|
||||
break copyFile
|
||||
}
|
||||
}
|
||||
copyFileSync(path, newPath)
|
||||
} catch (error) {
|
||||
console.error(`Error copying file: ${error}`)
|
||||
}
|
||||
|
||||
// remove the file from /static/models
|
||||
try {
|
||||
unlinkSync(path)
|
||||
} catch (error) {
|
||||
console.error(`Error removing file: ${error}`)
|
||||
}
|
||||
})
|
13
src/app.d.ts
vendored
13
src/app.d.ts
vendored
@ -1,13 +0,0 @@
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
12
src/app.html
12
src/app.html
@ -1,12 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
20
src/app/globals.css
Normal file
20
src/app/globals.css
Normal file
@ -0,0 +1,20 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
.shrimp {
|
||||
position: absolute !important;
|
||||
top: 0 !important;
|
||||
left: 0 !important;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
padding: 0% !important;
|
||||
}
|
||||
|
||||
/* Global styles adjustment */
|
||||
html,
|
||||
body {
|
||||
min-height: 100vh;
|
||||
min-width: 100vw;
|
||||
background-color: black; /* Ensure the background color is set here for full coverage */
|
||||
}
|
28
src/app/home/page.tsx
Normal file
28
src/app/home/page.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import Shrimp from '@/components/ShrimpRender';
|
||||
import Image from 'next/image';
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className='min-h-screen min-w-screen'>
|
||||
<Shrimp />
|
||||
<div className='absolute z-[1] bottom-0 left-1/2 transform -translate-x-1/2 text-white font-mono pb-10 text-center'>
|
||||
<p>SticksDev</p>
|
||||
<p>In shrimp, we trust.</p>
|
||||
|
||||
{/* Contact link */}
|
||||
<div className='text-blue-400 flex flex-row space-x-2'>
|
||||
<a href='/term' className='hover:text-blue-500 duration-200'>
|
||||
Open Terminal to Learn More
|
||||
</a>
|
||||
<p className='text-white'>or</p>
|
||||
<a
|
||||
href='mailto:sticks@teamhydra.dev'
|
||||
className='hover:text-blue-500 duration-200'
|
||||
>
|
||||
Get in touch
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
55
src/app/layout.tsx
Normal file
55
src/app/layout.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
import type { Metadata } from 'next';
|
||||
import { Inter } from 'next/font/google';
|
||||
import './globals.css';
|
||||
|
||||
const inter = Inter({ subsets: ['latin'] });
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<title>Stick's Portfolio</title>
|
||||
<meta name='title' content="Stick's Portfolio" />
|
||||
<meta
|
||||
name='description'
|
||||
content='Sometimes I make the computers do the things.'
|
||||
/>
|
||||
<meta name='theme-color' content='#0047AB'></meta>
|
||||
|
||||
<meta property='og:type' content='website' />
|
||||
<meta property='og:url' content='https://sticksdev.tech' />
|
||||
<meta property='og:title' content="Stick's Portfolio" />
|
||||
<meta
|
||||
property='og:description'
|
||||
content='Sometimes I make the computers do the things.'
|
||||
/>
|
||||
<meta
|
||||
property='og:image'
|
||||
content='https://img.sticks.ovh/stickspfpnew.png'
|
||||
/>
|
||||
|
||||
<meta property='twitter:card' content='summary_large_image' />
|
||||
<meta property='twitter:url' content='https://sticksdev.tech' />
|
||||
<meta property='twitter:title' content="Stick's Portfolio" />
|
||||
<meta
|
||||
property='twitter:description'
|
||||
content='Sometimes I make the computers do the things.'
|
||||
/>
|
||||
<meta
|
||||
property='twitter:image'
|
||||
content='https://sticksdev.techimages/meta-tags.png'
|
||||
/>
|
||||
</head>
|
||||
<link
|
||||
rel='icon'
|
||||
type='image/png'
|
||||
href='https://img.sticks.ovh/stickspfpnew.png'
|
||||
/>
|
||||
<body className={inter.className}>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
157
src/app/page.tsx
Normal file
157
src/app/page.tsx
Normal file
@ -0,0 +1,157 @@
|
||||
'use client';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
|
||||
function Home() {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const bootMessages = [
|
||||
'Initializing ShrimpBIOS v0.1.0... (c) 2024 SticksDev. All rights reserved.',
|
||||
'Checking Memory...',
|
||||
'...100KB OK',
|
||||
'...512KB OK',
|
||||
'...1024KB OK',
|
||||
'...2048KB OK',
|
||||
'...4096KB OK',
|
||||
'Memory OK',
|
||||
'Checking CPU...',
|
||||
'...CPU OK. Found Intel Pentium II 400MHz',
|
||||
'Running POST Cycle for Integrated Graphics...',
|
||||
'...Graphics OK. Found Intel i740',
|
||||
'Running POST Cycle for Audio...',
|
||||
'...Audio OK. Found SoundBlaster 16',
|
||||
'Running POST Cycle for Storage...',
|
||||
'...Storage OK. Found 1x 40GB HDD',
|
||||
'...Storage OK. Found 1x 1.44MB FDD',
|
||||
'...Storage OK. Found 1x CD-ROM Drive',
|
||||
'Preparing to boot from HDD...',
|
||||
'Booting from HDD...',
|
||||
'ShrimpOS v1.0.0 (c) 2024 SticksDev. All rights reserved.',
|
||||
'Welcome to ShrimpOS!',
|
||||
'In shrimp, we trust.',
|
||||
'Sending you to the home in 3...',
|
||||
'2...',
|
||||
'1...',
|
||||
'S:\\> home.exe',
|
||||
'Inlining ShrimpOS Home...',
|
||||
'Done!',
|
||||
'Preparing assets...',
|
||||
'Done!',
|
||||
'Loading ShrimpOS Home...',
|
||||
'Done!',
|
||||
'Welcome to ShrimpOS Home!',
|
||||
];
|
||||
|
||||
const [currentMessage, setCurrentMessage] = useState('');
|
||||
const [messageIndex, setMessageIndex] = useState(0);
|
||||
const [hasBootSequenceStarted, setHasBootSequenceStarted] = useState(false);
|
||||
const [isBootSequenceDone, setIsBootSequenceDone] = useState(false);
|
||||
const [skippedBootSequence, setSkippedBootSequence] = useState(false);
|
||||
|
||||
// Audio refs
|
||||
const bootAudio = useRef<HTMLAudioElement | null>(null);
|
||||
const welcomeAudio = useRef<HTMLAudioElement | null>(null);
|
||||
|
||||
function startBootSequence() {
|
||||
const bootAudio = new Audio('/bootup.mp3');
|
||||
bootAudio.play();
|
||||
setMessageIndex(1);
|
||||
setHasBootSequenceStarted(true);
|
||||
|
||||
// When bootAudio finsihes, play the welcome audio and goto /home
|
||||
bootAudio.onended = () => {
|
||||
const welcomeAudio = new Audio('/welcome.mp3');
|
||||
|
||||
// Fade out the main div
|
||||
const mainDiv = document.getElementById('main');
|
||||
if (!mainDiv) return;
|
||||
mainDiv.style.opacity = '0';
|
||||
|
||||
welcomeAudio.play();
|
||||
setIsBootSequenceDone(true);
|
||||
welcomeAudio.onended = () => {
|
||||
window.location.href = '/home';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
function handleSkipBootSequence() {
|
||||
setSkippedBootSequence(true);
|
||||
setMessageIndex(bootMessages.length);
|
||||
|
||||
// Kill all audios
|
||||
bootAudio.current?.pause();
|
||||
welcomeAudio.current?.pause();
|
||||
|
||||
window.location.href = '/home';
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasBootSequenceStarted) return;
|
||||
if (messageIndex < bootMessages.length) {
|
||||
const timer = setTimeout(() => {
|
||||
setCurrentMessage(bootMessages[messageIndex]);
|
||||
setMessageIndex(messageIndex + 1);
|
||||
}, 588); // Change the delay here to speed up or slow down the sequence
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [messageIndex, bootMessages, hasBootSequenceStarted]);
|
||||
|
||||
useEffect(() => {
|
||||
// Load the bootup sound
|
||||
bootAudio.current = new Audio('/bootup.mp3');
|
||||
welcomeAudio.current = new Audio('/welcome.mp3');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className='min-h-screen min-w-screen bg-black flex items-center justify-center'>
|
||||
{!hasBootSequenceStarted && (
|
||||
<div
|
||||
className={`flex flex-col items-center justify-center text-center text-white font-mono ${
|
||||
hasBootSequenceStarted ? 'hidden' : ''
|
||||
}`}
|
||||
>
|
||||
<p>You notice a mysterious computer in front of you.</p>
|
||||
<p>It seems to be off.</p>
|
||||
<button
|
||||
onClick={() => startBootSequence()}
|
||||
className='bg-blue-400 hover:bg-blue-500 text-white font-bold py-2 px-4 rounded mt-2'
|
||||
>
|
||||
Turn it on
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className='absolute top-0 left-0 text-white font-mono p-4 text-left transition-opacity duration-300'
|
||||
id='main'
|
||||
>
|
||||
{hasBootSequenceStarted &&
|
||||
bootMessages
|
||||
.slice(0, messageIndex)
|
||||
.map((message, index) => <p key={index}>{message}</p>)}
|
||||
</div>
|
||||
{/* Add skip boot sequence button in the right corner */}
|
||||
<button
|
||||
onClick={handleSkipBootSequence}
|
||||
className={`absolute top-0 right-0 text-white font-mono p-4 text-right transition-opacity duration-300 ${
|
||||
hasBootSequenceStarted ? '' : 'hidden' // Hide the button if the boot sequence hasn't started
|
||||
} ${
|
||||
skippedBootSequence ? 'hidden' : '' // Hide the button if the user has already skipped the boot sequence
|
||||
}`}
|
||||
>
|
||||
Skip Boot Sequence
|
||||
</button>
|
||||
{/* Center text to fade in once boot seq is done */}
|
||||
<div
|
||||
className={`flex flex-col items-center justify-center text-white text-center font-mono p-4 transition-opacity duration-500 ${
|
||||
isBootSequenceDone ? 'opacity-100' : 'opacity-0 hidden'
|
||||
}`}
|
||||
id='center'
|
||||
>
|
||||
<h1 className='text-2xl font-bold'>ShrimpOS</h1>
|
||||
<p className='text-gray-500'>Welcome.</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Home;
|
257
src/app/term/page.tsx
Normal file
257
src/app/term/page.tsx
Normal file
@ -0,0 +1,257 @@
|
||||
'use client';
|
||||
|
||||
import About from '@/components/About';
|
||||
import { Contact } from '@/components/Contact';
|
||||
import Experience from '@/components/Experince';
|
||||
import Projects from '@/components/Projects';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
|
||||
export default function Home() {
|
||||
const [input, setInput] = useState('');
|
||||
const [output, setOutput] = useState<React.ReactNode[]>([
|
||||
'ShrimpTerm v1.0.0',
|
||||
"Type 'help' for a list of commands.",
|
||||
'Press Tab for autocomplete, Escape to clear the current input.',
|
||||
]);
|
||||
const [suggestion, setSuggestion] = useState('');
|
||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||
|
||||
const keyAudio = useRef<HTMLAudioElement | null>(null);
|
||||
const enterAudio = useRef<HTMLAudioElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// Load the key press sound
|
||||
keyAudio.current = new Audio('/key.mp3');
|
||||
keyAudio.current.volume = 0.1;
|
||||
enterAudio.current = new Audio('/enter.mp3');
|
||||
enterAudio.current.volume = 0.1;
|
||||
inputRef.current?.focus();
|
||||
}, []);
|
||||
|
||||
const commands = [
|
||||
'help',
|
||||
'about',
|
||||
'clear',
|
||||
'projects',
|
||||
'experience',
|
||||
'contact',
|
||||
'back',
|
||||
];
|
||||
|
||||
const handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { value } = e.target;
|
||||
setInput(value);
|
||||
|
||||
// Generate suggestion only if 3 or more characters are entered
|
||||
if (value.trim().length < 3) {
|
||||
setSuggestion('');
|
||||
return;
|
||||
}
|
||||
|
||||
const matchedCommand = commands.find((command) =>
|
||||
command.startsWith(value.trim().toLowerCase()),
|
||||
);
|
||||
setSuggestion(matchedCommand ? matchedCommand : '');
|
||||
};
|
||||
|
||||
function processCommand(command: string) {
|
||||
switch (command.trim().toLowerCase()) {
|
||||
case 'help':
|
||||
setOutput((prevOutput) => [
|
||||
...prevOutput,
|
||||
'Available commands (click to autocomplete):',
|
||||
<div key='help'>
|
||||
<button
|
||||
key='clear'
|
||||
onClick={() => {
|
||||
setInput('help');
|
||||
inputRef.current?.focus();
|
||||
}}
|
||||
className='text-blue-500 hover:underline'
|
||||
>
|
||||
Help (this command)
|
||||
</button>
|
||||
{' - Display this help message'}
|
||||
</div>,
|
||||
<div key='about'>
|
||||
<button
|
||||
key='clear'
|
||||
onClick={() => {
|
||||
setInput('about');
|
||||
inputRef.current?.focus();
|
||||
}}
|
||||
className='text-blue-500 hover:underline'
|
||||
>
|
||||
About
|
||||
</button>
|
||||
{' - Learn more about Sticks and his projects'}
|
||||
</div>,
|
||||
<div key='projects'>
|
||||
<button
|
||||
key='clear'
|
||||
onClick={() => {
|
||||
setInput('projects');
|
||||
inputRef.current?.focus();
|
||||
}}
|
||||
className='text-blue-500 hover:underline'
|
||||
>
|
||||
Projects
|
||||
</button>
|
||||
{' - List of projects created by Sticks'}
|
||||
</div>,
|
||||
<div key='experience'>
|
||||
<button
|
||||
key='clear'
|
||||
onClick={() => {
|
||||
setInput('experience');
|
||||
inputRef.current?.focus();
|
||||
}}
|
||||
className='text-blue-500 hover:underline'
|
||||
>
|
||||
Experience
|
||||
</button>
|
||||
{" - View Sticks's experience and past positions"}
|
||||
</div>,
|
||||
<div key='contact'>
|
||||
<button
|
||||
key='clear'
|
||||
onClick={() => {
|
||||
setInput('contact');
|
||||
inputRef.current?.focus();
|
||||
}}
|
||||
className='text-blue-500 hover:underline'
|
||||
>
|
||||
Contact
|
||||
</button>
|
||||
{' - Get in touch with Sticks'}
|
||||
</div>,
|
||||
<div key='back'>
|
||||
<button
|
||||
key='clear'
|
||||
onClick={() => {
|
||||
setInput('back');
|
||||
inputRef.current?.focus();
|
||||
}}
|
||||
className='text-blue-500 hover:underline'
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
{' - Return to the home page'}
|
||||
</div>,
|
||||
<div key='clear'>
|
||||
<button
|
||||
key='clear'
|
||||
onClick={() => {
|
||||
setInput('clear');
|
||||
inputRef.current?.focus();
|
||||
}}
|
||||
className='text-blue-500 hover:underline'
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
{' - Clear the screen'}
|
||||
</div>,
|
||||
]);
|
||||
break;
|
||||
case 'about':
|
||||
setOutput((prevOutput) => [
|
||||
...prevOutput,
|
||||
<div key='about' className='flex flex-row'>
|
||||
<About />
|
||||
</div>,
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'projects':
|
||||
setOutput((prevOutput) => [
|
||||
...prevOutput,
|
||||
<div key='projects' className='flex flex-row'>
|
||||
<Projects />
|
||||
</div>,
|
||||
]);
|
||||
break;
|
||||
case 'experience':
|
||||
setOutput((prevOutput) => [
|
||||
...prevOutput,
|
||||
<div key='experience' className='flex flex-row'>
|
||||
<Experience />
|
||||
</div>,
|
||||
]);
|
||||
break;
|
||||
case 'back':
|
||||
window.location.href = '/home';
|
||||
break;
|
||||
case 'contact':
|
||||
setOutput((prevOutput) => [
|
||||
...prevOutput,
|
||||
<div key='contact'>
|
||||
<Contact />
|
||||
</div>,
|
||||
]);
|
||||
break;
|
||||
case 'clear':
|
||||
setOutput([
|
||||
'ShrimpTerm v1.0.0',
|
||||
"Type 'help' for a list of commands.",
|
||||
'Press Tab for autocomplete, Escape to clear the current input.',
|
||||
]);
|
||||
break;
|
||||
default:
|
||||
setOutput((prevOutput) => [
|
||||
...prevOutput,
|
||||
<div key='error'>
|
||||
<span className='text-red-500'>Error:</span> Bad command
|
||||
or file name: {command}
|
||||
</div>,
|
||||
]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const handleCommandInput = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === 'Enter') {
|
||||
enterAudio.current?.play();
|
||||
setOutput((prevOutput) => [...prevOutput, `S:\\> ${input}.exe`]);
|
||||
processCommand(input);
|
||||
setInput(''); // Clear the input
|
||||
setSuggestion(''); // Clear the suggestion
|
||||
} else if (e.key === 'Tab' && suggestion) {
|
||||
keyAudio.current?.play();
|
||||
e.preventDefault(); // Prevent the default tab behavior
|
||||
setInput(suggestion); // Set input to the full suggestion
|
||||
setSuggestion(''); // Clear the suggestion
|
||||
} else if (e.key === 'Escape') {
|
||||
keyAudio.current?.play();
|
||||
setInput(''); // Clear the input
|
||||
setSuggestion(''); // Clear the suggestion
|
||||
} else {
|
||||
keyAudio.current?.play();
|
||||
}
|
||||
};
|
||||
|
||||
// Adjustments to the component
|
||||
return (
|
||||
<div className='bg-black'>
|
||||
<div className='absolute z-[1] top-0 left-0 text-white font-mono p-10 overflow-auto min-h-screen min-w-screen'>
|
||||
{/* Back Link */}
|
||||
<a href='/home' className='hover:text-blue-500 duration-200'>
|
||||
< Back
|
||||
</a>
|
||||
{output.map((line, index) => (
|
||||
<p key={index}>{line}</p>
|
||||
))}
|
||||
<p className='text-gray-500'>
|
||||
{input && suggestion ? suggestion : ''}
|
||||
</p>
|
||||
<input
|
||||
ref={inputRef}
|
||||
className='bg-transparent text-white outline-none'
|
||||
value={input}
|
||||
onChange={handleInput}
|
||||
onKeyDown={handleCommandInput}
|
||||
placeholder='Type a command...'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
23
src/components/About.tsx
Normal file
23
src/components/About.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
'use client';
|
||||
|
||||
const AboutTxt = `
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ---- Reading file about_me.inf ----
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ---- File read successful ----
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Name: SticksDev (Tanner Sommers)
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Age: 21
|
||||
@@@@@@@@@@@****+++=@@@@@@@@@ Location: United States (UTC-5)
|
||||
@@@@@@@@@=-@@@@@@@@@@@@@@@@@ Occupation: Software Engineer/Freelancer
|
||||
@@@@@@@@@.:@@@@@@@@@@@@@@@@@ Skills: JavaScript, TypeScript, React, Svelte, Node.js, Python, C#, Java
|
||||
@@@@@@@@@@@------@@@@@@@@@@@ Interests: Web Development, Game Development, Cybersecurity
|
||||
@@@@@@@@@@@@@@@@@--@@@@@@@@@ Hobbies: Coding, Gaming, Chess, Music
|
||||
@@@@@@@@@==+++***@@@@@@@@@@@ Bio:
|
||||
@@@@@@@@@%%%%@@%@@@@@@@@@@@@ Hi! I'm Tanner, a software engineer and freelancer from the United States.
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@ I love coding, gaming, and learning new things. I'm always looking for new
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@ opportunities to grow and expand my skillset. Feel free to reach out to me
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@ if you have any questions or just want to chat!
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ---- End of file ----
|
||||
`;
|
||||
|
||||
export default function About() {
|
||||
return <pre className='text-white font-mono'>{AboutTxt}</pre>;
|
||||
}
|
32
src/components/Contact.tsx
Normal file
32
src/components/Contact.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
export function Contact() {
|
||||
return (
|
||||
<div>
|
||||
<h1 className='text-2xl font-bold font-mono'>Contact</h1>
|
||||
<p className='text-gray-500'>
|
||||
You can reach me at the following email address:
|
||||
</p>
|
||||
<a
|
||||
href='mailto:tanner@teamhydra.dev'
|
||||
className='text-blue-500 hover:underline'
|
||||
>
|
||||
tanner@teamhydra.dev
|
||||
</a>
|
||||
<br />
|
||||
-- or --
|
||||
<br />
|
||||
<a
|
||||
href='https://discord.gg/zira'
|
||||
className='text-blue-500 hover:underline'
|
||||
>
|
||||
Via Discord
|
||||
</a>
|
||||
<p className='text-gray-500'>
|
||||
Please use the #other-support channel to get in touch with me. My
|
||||
username is sticksdev.
|
||||
</p>
|
||||
<p className='text-gray-500'>
|
||||
I look forward to hearing from you soon :)
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
86
src/components/Experince.tsx
Normal file
86
src/components/Experince.tsx
Normal file
@ -0,0 +1,86 @@
|
||||
'use strict';
|
||||
'use client';
|
||||
import { useState } from 'react';
|
||||
|
||||
const experience = [
|
||||
`
|
||||
@@@@@@@@@@
|
||||
@@@@@*:@@@@@
|
||||
@#*@+**-@:@@
|
||||
@#@@@ @@@**@**@:*@@ @@@*@
|
||||
@@+@@@:@@@@@*%*@**@*.%@@@@@:@@@+@@
|
||||
@@@@@@@@@@@@@@*@*:#*@@@@@***:@#@@@**:*@*@@@@@@@@@@@%@@ Company Name: Team Hydra
|
||||
@@@%%@@***********@@********@@**+*******+@@**@@@ Position: Software Developer
|
||||
@@@#%@********+*@********@*************@@@ Start Date: 2020-09-01
|
||||
@@@@%********.*@*%**@*@+.*********@@@@ End: Present
|
||||
@@@@#**@*%**+@@*@@@@+@@+****@**+@@@@ About:
|
||||
@@@@**@@*****@@*@@=@@*****@@%*@@@@ I've worked with team hydra on a variety of projects,
|
||||
@ @@+*@@@*****@#@@*****@@@#*@@ @ including developing web applications, mobile apps, discord bots,
|
||||
@@@ @@%%@@@@@***@@***@@@@@%@@@ @@@ and APIs. It's a great team to work with, and I've learned a lot.
|
||||
@@@%@@@@*****+**@@@@%@@@ I highly recommend them to anyone looking for software development
|
||||
@@@%%%***#@**@****%%%@@@ services and a career in software development.
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@@ @@
|
||||
`,
|
||||
`
|
||||
*###########*
|
||||
################*
|
||||
######## *####
|
||||
###### *
|
||||
*####*
|
||||
##### #########
|
||||
##### ######### ordon food services
|
||||
#####* ######### Position: Network Engineer/IT Specialist
|
||||
###### *#### Start Date: 2022-06-01
|
||||
#######* =###### End: 2024-06-01
|
||||
################# About: I worked with Gordon food services to help maintain their network infrastructure
|
||||
############* and provide IT support to their employees. I was responsible for troubleshooting network
|
||||
####### issues, setting up new network equipment, and providing support to employees with IT issues.
|
||||
#### I was laid off, but I enjoyed my time there and learned a lot about network engineering and
|
||||
* IT support.
|
||||
`,
|
||||
];
|
||||
|
||||
export default function Experience() {
|
||||
const [index, setIndex] = useState(0);
|
||||
|
||||
const handleNext = () => {
|
||||
if (index < experience.length - 1) {
|
||||
setIndex(index + 1);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePrev = () => {
|
||||
if (index > 0) {
|
||||
setIndex(index - 1);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1 className='text-2xl font-bold font-mono'>Experience</h1>
|
||||
<p className='text-gray-500'>
|
||||
Use the buttons below to navigate through my experience.
|
||||
</p>
|
||||
<div className='flex justify-between'>
|
||||
<button
|
||||
onClick={handlePrev}
|
||||
className='text-blue-500 hover:underline'
|
||||
disabled={index === 0}
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
<button
|
||||
onClick={handleNext}
|
||||
className='text-blue-500 hover:underline'
|
||||
disabled={index === experience.length - 1}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
<div className=''>
|
||||
<pre className='whitespace-pre-wrap'>{experience[index]}</pre>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
59
src/components/Projects.tsx
Normal file
59
src/components/Projects.tsx
Normal file
@ -0,0 +1,59 @@
|
||||
export const projects = [
|
||||
{
|
||||
title: 'BambuConnect',
|
||||
description: 'A simple 3rd party client for managing your 3D printer.',
|
||||
link: 'https://github.com/SticksDev/BambuConnect',
|
||||
},
|
||||
{
|
||||
title: 'VRDCN_NetworkTest',
|
||||
description:
|
||||
'A simple network test for a VR Streaming service. Written in Go.',
|
||||
link: 'https://github.com/SticksDev/VRCDN_NetworkTest',
|
||||
},
|
||||
{
|
||||
title: 'Runic Spells',
|
||||
description:
|
||||
'A simple spell system for Minecraft using Java and PaperMC APIs.',
|
||||
link: 'https://github.com/SticksDev/runic_spells',
|
||||
},
|
||||
];
|
||||
|
||||
export default function Projects() {
|
||||
// Step 1: Calculate maximum lengths
|
||||
const maxTitleLength = Math.max(
|
||||
...projects.map((project) => project.title.length),
|
||||
);
|
||||
const maxDescriptionLength = Math.max(
|
||||
...projects.map((project) => project.description.length),
|
||||
);
|
||||
const maxLinkLength = Math.max(
|
||||
...projects.map((project) => project.link.length),
|
||||
);
|
||||
|
||||
// Step 2: Prepare projects with padded strings for rendering
|
||||
const preparedProjects = projects.map((project) => ({
|
||||
...project,
|
||||
title: project.title.padEnd(maxTitleLength, ' '),
|
||||
description: project.description.padEnd(maxDescriptionLength, ' '),
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className='bg-black font-mono text-white'>
|
||||
<h1 className='text-white font-mono text-md mb-4'>
|
||||
--- Reading database projects.db ---<br></br>
|
||||
Found {projects.length} projects in database. Displaying all projects:
|
||||
</h1>
|
||||
{preparedProjects.map((project, index) => (
|
||||
<div key={index} className='flex flex-row'>
|
||||
<p>{project.title}</p> |
|
||||
<p> {project.description}</p>|
|
||||
<a href={project.link} className="hover:text-blue-500 duration-200" target="blank"> {project.link}</a>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<h1 className='text-white font-mono text-md mt-4'>
|
||||
--- End of database ---
|
||||
</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
67
src/components/ShrimpRender.tsx
Normal file
67
src/components/ShrimpRender.tsx
Normal file
@ -0,0 +1,67 @@
|
||||
'use client';
|
||||
import { Canvas, useFrame } from '@react-three/fiber';
|
||||
import * as THREE from 'three';
|
||||
import React, { useRef } from 'react';
|
||||
import { AsciiRenderer, OrbitControls, useGLTF } from '@react-three/drei';
|
||||
import { GLTF } from 'three-stdlib';
|
||||
|
||||
type GLTFResult = GLTF & {
|
||||
nodes: {
|
||||
Mesh_Mesh_head_geo001_lambert2SG001: THREE.Mesh;
|
||||
};
|
||||
materials: {
|
||||
['lambert2SG.001']: THREE.MeshStandardMaterial;
|
||||
};
|
||||
};
|
||||
|
||||
export function ShrimpModel(props: JSX.IntrinsicElements['group']) {
|
||||
const { nodes, materials } = useGLTF('/shrimp_smol.glb') as GLTFResult;
|
||||
const groupRef = useRef<THREE.Group>(null!);
|
||||
useFrame((state, delta) => (groupRef.current.rotation.z += delta * .5))
|
||||
|
||||
return (
|
||||
<group {...props} ref={groupRef} dispose={null}>
|
||||
<mesh
|
||||
castShadow
|
||||
receiveShadow
|
||||
geometry={nodes.Mesh_Mesh_head_geo001_lambert2SG001.geometry}
|
||||
material={materials['lambert2SG.001']}
|
||||
rotation={[-Math.PI / 2, 0, 0]}
|
||||
/>
|
||||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
useGLTF.preload('/shrimp.glb');
|
||||
|
||||
function CameraHelper() {
|
||||
const camera = new THREE.PerspectiveCamera(60, 1.77, 1, 3);
|
||||
return (
|
||||
<group position={[0.5, 40, 8.5]} rotation={new THREE.Euler(-1.5, 0, 0)}>
|
||||
<cameraHelper args={[camera]} />
|
||||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Shrimp() {
|
||||
const eular = new THREE.Euler(-1.5, 0, 0);
|
||||
return (
|
||||
<>
|
||||
<Canvas
|
||||
className='shrimp'
|
||||
camera={{
|
||||
position: [0.4, 40, 11],
|
||||
rotation: eular,
|
||||
fov: 60,
|
||||
aspect: 1.77,
|
||||
near: 1,
|
||||
}}
|
||||
>
|
||||
<color attach='background' args={['black']} />
|
||||
<ambientLight intensity={Math.PI / 2} />
|
||||
<ShrimpModel position={[0, -1, 0]} rotation={[0, 0, 0]} />
|
||||
<AsciiRenderer fgColor='red' />
|
||||
</Canvas>
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Canvas } from '@threlte/core'
|
||||
import Scene from './Scene.svelte'
|
||||
</script>
|
||||
|
||||
<Canvas>
|
||||
<Scene />
|
||||
</Canvas>
|
@ -1,60 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { T, useFrame } from '@threlte/core'
|
||||
|
||||
let rotation = 0
|
||||
useFrame(() => {
|
||||
rotation += 0.001
|
||||
})
|
||||
</script>
|
||||
|
||||
<T.Group rotation.y={rotation}>
|
||||
<T.PerspectiveCamera
|
||||
makeDefault
|
||||
position={[-10, 10, 10]}
|
||||
fov={15}
|
||||
on:create={({ ref }) => {
|
||||
ref.lookAt(0, 1, 0)
|
||||
}}
|
||||
/>
|
||||
</T.Group>
|
||||
|
||||
<!-- Floor -->
|
||||
<T.Mesh rotation.x={(90 * Math.PI) / 180}>
|
||||
<T.CircleGeometry args={[3, 16]} />
|
||||
<T.MeshBasicMaterial
|
||||
color="#666666"
|
||||
wireframe
|
||||
/>
|
||||
</T.Mesh>
|
||||
|
||||
<T.DirectionalLight
|
||||
intensity={0.8}
|
||||
position.x={5}
|
||||
position.y={10}
|
||||
/>
|
||||
<T.AmbientLight intensity={0.2} />
|
||||
|
||||
<T.Mesh
|
||||
position.y={1.2}
|
||||
position.z={-0.75}
|
||||
>
|
||||
<T.BoxGeometry />
|
||||
<T.MeshStandardMaterial color="#0059BA" />
|
||||
</T.Mesh>
|
||||
|
||||
<T.Mesh
|
||||
position={[1.2, 1.5, 0.75]}
|
||||
rotation.x={5}
|
||||
rotation.y={71}
|
||||
>
|
||||
<T.TorusKnotGeometry args={[0.5, 0.15, 100, 12, 2, 3]} />
|
||||
<T.MeshStandardMaterial color="#F85122" />
|
||||
</T.Mesh>
|
||||
|
||||
<T.Mesh
|
||||
position={[-1.4, 1.5, 0.75]}
|
||||
rotation={[-5, 128, 10]}
|
||||
>
|
||||
<T.IcosahedronGeometry />
|
||||
<T.MeshStandardMaterial color="#F8EBCE" />
|
||||
</T.Mesh>
|
@ -1,5 +0,0 @@
|
||||
# Threlte Model Pipeline Components
|
||||
|
||||
This directory holds automatically generated Threlte components from GLTF models.
|
||||
|
||||
Place your models in `static/models` and run `npm run model-pipeline:run` to generate the components.
|
@ -1 +0,0 @@
|
||||
// place files you want to import through the `$lib` alias in this folder.
|
@ -1,20 +0,0 @@
|
||||
<script lang="ts">
|
||||
import App from '$lib/components/App.svelte'
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<App />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
:global(body) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: rgb(13, 19, 32);
|
||||
background: linear-gradient(180deg, rgba(13, 19, 32, 1) 0%, rgba(8, 12, 21, 1) 100%);
|
||||
}
|
||||
</style>
|
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
@ -1,18 +0,0 @@
|
||||
import adapter from '@sveltejs/adapter-auto';
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
||||
// for more information about preprocessors
|
||||
preprocess: vitePreprocess(),
|
||||
|
||||
kit: {
|
||||
// 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.
|
||||
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
||||
adapter: adapter()
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
20
tailwind.config.ts
Normal file
20
tailwind.config.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import type { Config } from "tailwindcss";
|
||||
|
||||
const config: Config = {
|
||||
content: [
|
||||
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
backgroundImage: {
|
||||
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
|
||||
"gradient-conic":
|
||||
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
export default config;
|
@ -1,19 +1,26 @@
|
||||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler"
|
||||
}
|
||||
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
|
||||
// except $lib which is handled by https://kit.svelte.dev/docs/configuration#files
|
||||
//
|
||||
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||
"compilerOptions": {
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
@ -1,6 +0,0 @@
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()]
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user