Skip to content

Commit 44b670d

Browse files
committed
addeadded skull
1 parent 28d6b37 commit 44b670d

File tree

9 files changed

+178
-3
lines changed

9 files changed

+178
-3
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
"version": "1.0.0",
44
"private": true,
55
"scripts": {
6-
"dev": "bun --hot ./public/index.html",
6+
"dev": "bun run server.js",
7+
"dev:old": "bun --hot ./public/index.html",
78
"format": "prettier --write *.html *.css"
89
},
910
"devDependencies": {
48.7 KB
Loading
22 MB
Binary file not shown.

public/favicon.ico

46.9 KB
Binary file not shown.

public/index.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@
5454
<body>
5555
<code id="background"></code>
5656
<script src="scripts/index.js"></script>
57+
58+
<!-- Three.js dependencies for skull viewer -->
59+
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
60+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js"></script>
61+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/loaders/STLLoader.js"></script>
62+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/effects/AsciiEffect.js"></script>
63+
5764
<div id="content">
5865
<header>
5966
<h1>Soohoon Choi</h1>

public/scripts/index.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,23 @@
1-
const currentMinute = new Date().getMinutes();
2-
const scriptName = (currentMinute % 2 === 0) ? 'life' : 'donut';
1+
const second = new Date().getSeconds();
2+
const scriptName = (() => {
3+
switch (second % 3) {
4+
case 0:
5+
return 'life';
6+
case 1:
7+
return 'donut';
8+
default:
9+
return 'skull';
10+
}
11+
})();
312

413
if (scriptName === 'life') {
514
import('./life.js').catch(error => {
615
console.error('Error loading life script:', error);
716
});
17+
} else if (scriptName === 'skull') {
18+
import('./skull.js').catch(error => {
19+
console.error('Error loading skull script:', error);
20+
});
821
} else {
922
import('./donut.js').catch(error => {
1023
console.error('Error loading donut script:', error);

public/scripts/life.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ const gliderGenerator = (startX, startY, state, rotation = 0) => {
6161
}
6262

6363
let state = Array(HEIGHT).fill().map(() => Array(WIDTH).fill(SPACE))
64+
gliderGenerator(2, 0, state, 0)
6465
gliderGenerator(WIDTH - 39, HEIGHT - 12, state, 180)
66+
gliderGenerator(2, HEIGHT - 39, state, 270)
67+
gliderGenerator(WIDTH - 12, 2, state, 90)
6568

6669
let lifeInterval = setInterval(() => {
6770
targetElement.innerHTML = state.map(row => row.join('')).join(NEWLINE)

public/scripts/skull.js

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
const clock = new THREE.Clock();
2+
const myMesh = new THREE.Mesh();
3+
4+
const scene = new THREE.Scene();
5+
scene.background = new THREE.Color(1, 1, 1);
6+
7+
const ambientLight = new THREE.AmbientLight(0xffffff, 0.1);
8+
scene.add(ambientLight);
9+
10+
const pointLight = new THREE.PointLight(0xffffff, 0.9, 0, 0.8);
11+
pointLight.position.set(100, 100, 400);
12+
scene.add(pointLight);
13+
14+
15+
const stlLoader = new THREE.STLLoader();
16+
17+
const material = new THREE.MeshStandardMaterial({
18+
roughness: 0.9,
19+
metalness: 0.0
20+
});
21+
material.flatShading = true;
22+
material.side = THREE.DoubleSide;
23+
24+
const sizes = {
25+
width: window.innerWidth,
26+
height: window.innerHeight
27+
};
28+
29+
const camera = new THREE.PerspectiveCamera(45, sizes.width / sizes.height, 0.1, 2000);
30+
const renderer = new THREE.WebGLRenderer();
31+
32+
let effect;
33+
let controls;
34+
35+
let characters = ' .:-+*=%@#';
36+
const effectSize = { amount: .15 };
37+
let ASCIIColor = 'black';
38+
39+
function createEffect() {
40+
effect = new THREE.AsciiEffect(renderer, characters, { invert: false, resolution: effectSize.amount });
41+
effect.setSize(sizes.width, sizes.height);
42+
effect.domElement.style.color = ASCIIColor;
43+
}
44+
45+
createEffect();
46+
47+
const targetElement = document.getElementById('background');
48+
targetElement.appendChild(effect.domElement);
49+
50+
stlLoader.load('/assets/models/spinosaurus.stl', function (geometry) {
51+
initializeSkull(geometry);
52+
});
53+
54+
function initializeSkull(geometry) {
55+
myMesh.material = material;
56+
myMesh.geometry = geometry;
57+
58+
geometry.computeVertexNormals();
59+
myMesh.geometry.center();
60+
myMesh.geometry.computeBoundingBox();
61+
62+
const bbox = myMesh.geometry.boundingBox;
63+
myMesh.position.set(0, 0, 0);
64+
myMesh.rotation.x = 0.2;
65+
66+
camera.position.x = bbox.max.x * 9;
67+
camera.position.y = 0;
68+
camera.position.z = 0;
69+
camera.lookAt(0, 0, 0);
70+
71+
scene.add(myMesh);
72+
73+
function tick() {
74+
const elapsedTime = clock.getElapsedTime();
75+
const angle = elapsedTime * 0.4;
76+
const radius = bbox.max.x * 0.6;
77+
78+
pointLight.position.x = bbox.max.x * 1 + Math.sin(angle * 0.5) * radius * 0.3;
79+
pointLight.position.y = Math.cos(angle) * radius;
80+
pointLight.position.z = Math.sin(angle) * radius * 3;
81+
82+
effect.render(scene, camera);
83+
window.requestAnimationFrame(tick);
84+
}
85+
86+
tick();
87+
}
88+
89+
window.addEventListener('resize', function () {
90+
camera.aspect = window.innerWidth / window.innerHeight;
91+
camera.updateProjectionMatrix();
92+
renderer.setSize(window.innerWidth, window.innerHeight);
93+
effect.setSize(window.innerWidth, window.innerHeight);
94+
});

server.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { serve } from "bun";
2+
import { join } from "path";
3+
4+
const PUBLIC_DIR = "./public";
5+
6+
serve({
7+
port: 3000,
8+
async fetch(request) {
9+
const url = new URL(request.url);
10+
let pathname = url.pathname;
11+
12+
// Default to index.html for root
13+
if (pathname === "/") {
14+
pathname = "/index.html";
15+
}
16+
17+
// Construct file path
18+
const filePath = join(PUBLIC_DIR, pathname);
19+
const file = Bun.file(filePath);
20+
21+
// Check if file exists
22+
const exists = await file.exists();
23+
if (!exists) {
24+
// Fallback to index.html for SPA routing
25+
const indexFile = Bun.file(join(PUBLIC_DIR, "index.html"));
26+
return new Response(indexFile, {
27+
headers: { "Content-Type": "text/html" }
28+
});
29+
}
30+
31+
// Serve the file with appropriate content type
32+
const contentType = getContentType(pathname);
33+
return new Response(file, {
34+
headers: { "Content-Type": contentType }
35+
});
36+
},
37+
development: true,
38+
});
39+
40+
function getContentType(pathname) {
41+
const ext = pathname.split('.').pop()?.toLowerCase();
42+
const types = {
43+
'html': 'text/html',
44+
'js': 'application/javascript',
45+
'css': 'text/css',
46+
'stl': 'application/octet-stream',
47+
'3mf': 'application/octet-stream',
48+
'ico': 'image/x-icon',
49+
'png': 'image/png',
50+
'jpg': 'image/jpeg',
51+
'jpeg': 'image/jpeg',
52+
'svg': 'image/svg+xml'
53+
};
54+
return types[ext] || 'application/octet-stream';
55+
}
56+
57+
console.log("Server running at http://localhost:3000");

0 commit comments

Comments
 (0)