Daveroby13 commited on
Commit
80c0783
·
verified ·
1 Parent(s): 2371402

Can you finish the project to make the whole thing give me a let me be able to walk around and feel what it's like

Browse files
Files changed (6) hide show
  1. README.md +8 -5
  2. index.html +155 -19
  3. playground.html +90 -0
  4. playground.js +297 -0
  5. script.js +228 -0
  6. style.css +77 -19
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Squirrelvision 3d Playground Explorer
3
- emoji: 💻
4
- colorFrom: green
5
- colorTo: green
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
  ---
2
+ title: SquirrelVision 3D Playground Explorer 🐿️
3
+ colorFrom: red
4
+ colorTo: blue
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://huggingface.co/deepsite).
index.html CHANGED
@@ -1,19 +1,155 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>SquirrelView 3D Sandbox Explorer</title>
7
+ <link rel="icon" type="image/x-icon" href="/static/favicon.ico">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
10
+ <script src="https://unpkg.com/feather-icons"></script>
11
+ <link rel="stylesheet" href="style.css">
12
+ </head>
13
+ <body class="bg-gradient-to-br from-gray-900 to-gray-800 min-h-screen text-white">
14
+ <!-- Navigation Component -->
15
+ <script src="components/navigation.js"></script>
16
+ <custom-navigation></custom-navigation>
17
+
18
+ <!-- Main Content -->
19
+ <main class="container mx-auto px-4 py-8">
20
+ <!-- Hero Section -->
21
+ <section class="text-center mb-16">
22
+ <h1 class="text-5xl md:text-7xl font-bold mb-6 bg-gradient-to-r from-green-400 to-blue-500 bg-clip-text text-transparent">
23
+ SquirrelView 3D Sandbox
24
+ </h1>
25
+ <p class="text-xl md:text-2xl text-gray-300 mb-8 max-w-3xl mx-auto">
26
+ A powerful 3D model testing environment with full controller support.
27
+ Walk around, interact with assets, and test your models in real-time.
28
+ </p>
29
+
30
+ <!-- Quick Actions -->
31
+ <div class="flex flex-wrap justify-center gap-4 mb-12">
32
+ <button class="bg-green-600 hover:bg-green-700 px-6 py-3 rounded-lg font-semibold transition-all transform hover:scale-105">
33
+ <i data-feather="download" class="inline mr-2"></i>Download Python Script
34
+ </button>
35
+ <button class="bg-blue-600 hover:bg-blue-700 px-6 py-3 rounded-lg font-semibold transition-all transform hover:scale-105">
36
+ <i data-feather="book-open" class="inline mr-2"></i>View Documentation
37
+ </button>
38
+ </div>
39
+ </section>
40
+
41
+ <!-- Features Grid -->
42
+ <section class="mb-16">
43
+ <h2 class="text-3xl md:text-4xl font-bold text-center mb-12">Powerful Features</h2>
44
+ <div class="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
45
+ <!-- Feature 1 -->
46
+ <div class="bg-gray-800 rounded-xl p-6 hover:bg-gray-700 transition-all">
47
+ <div class="w-12 h-12 bg-green-500 rounded-lg flex items-center justify-center mb-4">
48
+ <i data-feather="box" class="text-white"></i>
49
+ </div>
50
+ <h3 class="text-xl font-bold mb-2">Multi-Format Support</h3>
51
+ <p class="text-gray-300">Import .glb, .obj, and .stl files with seamless integration into your 3D world.</p>
52
+ </div>
53
+
54
+ <!-- Feature 2 -->
55
+ <div class="bg-gray-800 rounded-xl p-6 hover:bg-gray-700 transition-all">
56
+ <div class="w-12 h-12 bg-blue-500 rounded-lg flex items-center justify-center mb-4">
57
+ <i data-feather="gamepad" class="text-white"></i>
58
+ </div>
59
+ <h3 class="text-xl font-bold mb-2">PS4 Controller Support</h3>
60
+ <p class="text-gray-300">Full analog stick support and button mapping for intuitive navigation.</p>
61
+ </div>
62
+
63
+ <!-- Feature 3 -->
64
+ <div class="bg-gray-800 rounded-xl p-6 hover:bg-gray-700 transition-all">
65
+ <div class="w-12 h-12 bg-purple-500 rounded-lg flex items-center justify-center mb-4">
66
+ <i data-feather="eye" class="text-white"></i>
67
+ </div>
68
+ <h3 class="text-xl font-bold mb-2">Real-time Inspection</h3>
69
+ <p class="text-gray-300">Toggle between first-person and free-fly modes for detailed model analysis.</p>
70
+ </div>
71
+
72
+ <!-- Feature 4 -->
73
+ <div class="bg-gray-800 rounded-xl p-6 hover:bg-gray-700 transition-all">
74
+ <div class="w-12 h-12 bg-yellow-500 rounded-lg flex items-center justify-center mb-4">
75
+ <i data-feather="save" class="text-white"></i>
76
+ </div>
77
+ <h3 class="text-xl font-bold mb-2">Save/Load Worlds</h3>
78
+ <p class="text-gray-300">Preserve your sandbox configurations and asset placements between sessions.</p>
79
+ </div>
80
+
81
+ <!-- Feature 5 -->
82
+ <div class="bg-gray-800 rounded-xl p-6 hover:bg-gray-700 transition-all">
83
+ <div class="w-12 h-12 bg-red-500 rounded-lg flex items-center justify-center mb-4">
84
+ <i data-feather="cpu" class="text-white"></i>
85
+ </div>
86
+ <h3 class="text-xl font-bold mb-2">Interactive NPCs</h3>
87
+ <p class="text-gray-300">Squirrel NPCs provide UI triggers and helpful guidance throughout your testing.</p>
88
+ </div>
89
+
90
+ <!-- Feature 6 -->
91
+ <div class="bg-gray-800 rounded-xl p-6 hover:bg-gray-700 transition-all">
92
+ <div class="w-12 h-12 bg-indigo-500 rounded-lg flex items-center justify-center mb-4">
93
+ <i data-feather="sliders" class="text-white"></i>
94
+ </div>
95
+ <h3 class="text-xl font-bold mb-2">Asset Inspector</h3>
96
+ <p class="text-gray-300">Real-time property editing including rotation, scale, and material toggles.</p>
97
+ </div>
98
+ </div>
99
+ </section>
100
+
101
+ <!-- Code Preview -->
102
+ <section class="bg-gray-800 rounded-xl p-8 mb-16">
103
+ <h2 class="text-3xl font-bold mb-6">Python Script Preview</h2>
104
+ <div class="bg-gray-900 rounded-lg p-4 overflow-x-auto">
105
+ <pre><code class="language-python">import ursina as u
106
+ from ursina.prefabs.first_person_controller import FirstPersonController
107
+
108
+ # Initialize Ursina application
109
+ app = u.Ursina()
110
+
111
+ # Create basic world geometry
112
+ ground = u.Entity(model='plane', scale=(100,1,100), color=u.color.green)
113
+ sky = u.Sky()
114
+
115
+ # Player controller with PS4 support
116
+ player = FirstPersonController()
117
+ player.speed = 8
118
+
119
+ # Squirrel NPC for UI interactions
120
+ squirrel = u.Entity(
121
+ model='cube',
122
+ color=u.color.orange,
123
+ position=(5, 0.5, 5),
124
+ scale=(1, 1, 1)
125
+ )
126
+
127
+ def update():
128
+ # PS4 controller input handling
129
+ if u.held_keys['gamepad left stick x']:
130
+ player.x += u.time.dt * u.held_keys['gamepad left stick x'] * player.speed
131
+ # Add more controller mappings...
132
+
133
+ app.run()</code></pre>
134
+ </div>
135
+ </section>
136
+
137
+ <!-- Download Section -->
138
+ <section class="text-center bg-gray-800 rounded-xl p-8">
139
+ <h2 class="text-3xl font-bold mb-4">Ready to Explore?</h2>
140
+ <p class="text-gray-300 mb-6">Download the complete Python script and start testing your 3D models today!</p>
141
+ <button class="bg-gradient-to-r from-green-500 to-blue-600 hover:from-green-600 hover:to-blue-700 px-8 py-4 rounded-lg font-bold text-lg transition-all transform hover:scale-105">
142
+ <i data-feather="download" class="inline mr-2"></i>Download Full Script
143
+ </button>
144
+ </section>
145
+ </main>
146
+
147
+ <!-- Footer Component -->
148
+ <script src="Can you finish the project to make the whole thing give me let me be able to walk around and feel what it's like to do this oPpcomponents/footer.js"></script>
149
+ <custom-footer></custom-footer>
150
+
151
+ <script src="script.js"></script>
152
+ <script>feather.replace();</script>
153
+ <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
154
+ </body>
155
+ </html>
playground.html ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>SquirrelVision 3D Playground</title>
7
+ <link rel="icon" type="image/x-icon" href="/static/favicon.ico">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/jsm/controls/PointerLockControls.js"></script>
11
+ <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/jsm/loaders/GLTFLoader.js"></script>
12
+ <link rel="stylesheet" href="style.css">
13
+ </head>
14
+ <body class="bg-gray-900 text-white overflow-hidden">
15
+ <!-- Navigation -->
16
+ <script src="components/navigation.js"></script>
17
+ <custom-navigation></custom-navigation>
18
+
19
+ <!-- Game Container -->
20
+ <div id="gameContainer" class="w-full h-screen relative">
21
+ <!-- Loading Screen -->
22
+ <div id="loadingScreen" class="absolute inset-0 bg-gray-900 flex flex-col items-center justify-center z-50">
23
+ <div class="text-4xl font-bold mb-4 bg-gradient-to-r from-green-400 to-blue-500 bg-clip-text text-transparent">
24
+ SquirrelVision 3D Playground
25
+ </div>
26
+ <div class="text-xl text-gray-300 mb-8">Loading your adventure...</div>
27
+ <div class="w-64 h-2 bg-gray-700 rounded-full overflow-hidden">
28
+ <div id="progressBar" class="h-full bg-gradient-to-r from-green-500 to-blue-600 transition-all duration-300"></div>
29
+ </div>
30
+ <div class="mt-4 text-gray-400" id="loadingText">Initializing 3D engine...</div>
31
+ </div>
32
+
33
+ <!-- UI Overlay -->
34
+ <div id="uiOverlay" class="absolute inset-0 pointer-events-none z-40 hidden">
35
+ <!-- Crosshair -->
36
+ <div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-4 h-4">
37
+ <div class="absolute top-1/2 left-0 w-2 h-0.5 bg-white opacity-60"></div>
38
+ <div class="absolute top-1/2 right-0 w-2 h-0.5 bg-white opacity-60"></div>
39
+ <div class="absolute left-1/2 top-0 h-2 w-0.5 bg-white opacity-60"></div>
40
+ <div class="absolute left-1/2 bottom-0 h-2 w-0.5 bg-white opacity-60"></div>
41
+ </div>
42
+
43
+ <!-- Instructions -->
44
+ <div class="absolute bottom-4 left-4 bg-black bg-opacity-50 p-4 rounded-lg pointer-events-auto">
45
+ <div class="text-sm space-y-2">
46
+ <div class="flex items-center space-x-2">
47
+ <span class="bg-gray-700 px-2 py-1 rounded text-xs">WASD</span>
48
+ <span>Move around</span>
49
+ </div>
50
+ <div class="flex items-center space-x-2">
51
+ <span class="bg-gray-700 px-2 py-1 rounded text-xs">Mouse</span>
52
+ <span>Look around</span>
53
+ </div>
54
+ <div class="flex items-center space-x-2">
55
+ <span class="bg-gray-700 px-2 py-1 rounded text-xs">Space</span>
56
+ <span>Jump</span>
57
+ </div>
58
+ <div class="flex items-center space-x-2">
59
+ <span class="bg-gray-700 px-2 py-1 rounded text-xs">E</span>
60
+ <span>Interact</span>
61
+ </div>
62
+ </div>
63
+ </div>
64
+
65
+ <!-- Interaction Prompt -->
66
+ <div id="interactionPrompt" class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-8 bg-black bg-opacity-70 px-4 py-2 rounded-lg text-center hidden">
67
+ <div class="text-sm">Press <span class="bg-gray-700 px-2 py-1 rounded text-xs">E</span> to interact</div>
68
+ </div>
69
+ </div>
70
+
71
+ <!-- Start Screen -->
72
+ <div id="startScreen" class="absolute inset-0 bg-black bg-opacity-80 flex flex-col items-center justify-center z-30">
73
+ <div class="text-6xl font-bold mb-4 bg-gradient-to-r from-green-400 to-blue-500 bg-clip-text text-transparent">
74
+ SquirrelVision
75
+ </div>
76
+ <div class="text-2xl text-gray-300 mb-8">3D Playground Explorer</div>
77
+ <button id="startButton" class="bg-gradient-to-r from-green-500 to-blue-600 hover:from-green-600 hover:to-blue-700 px-8 py-4 rounded-lg font-bold text-xl transition-all transform hover:scale-105">
78
+ Enter Playground
79
+ </button>
80
+ <div class="mt-8 text-gray-400 text-center max-w-md">
81
+ Explore the 3D world, interact with objects, and experience the power of our sandbox environment.
82
+ </div>
83
+ </div>
84
+ </div>
85
+
86
+ <!-- Game Script -->
87
+ <script src="playground.js"></script>
88
+ <script src="components/navigation.js"></script>
89
+ </body>
90
+ </html>
playground.js ADDED
@@ -0,0 +1,297 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ```javascript
2
+ // SquirrelVision 3D Playground - Main Game Script
3
+
4
+ class SquirrelVisionPlayground {
5
+ constructor() {
6
+ this.scene = null;
7
+ this.camera = null;
8
+ this.renderer = null;
9
+ this.controls = null;
10
+ this.objects = [];
11
+ this.isPlaying = false;
12
+ this.moveForward = false;
13
+ this.moveBackward = false;
14
+ this.moveLeft = false;
15
+ this.moveRight = false;
16
+ this.canJump = false;
17
+ this.prevTime = performance.now();
18
+ this.velocity = new THREE.Vector3();
19
+ this.direction = new THREE.Vector3();
20
+ this.interactiveObjects = [];
21
+
22
+ this.init();
23
+ }
24
+
25
+ async init() {
26
+ // Update loading progress
27
+ this.updateLoadingProgress(10, 'Creating 3D scene...');
28
+
29
+ // Create scene
30
+ this.scene = new THREE.Scene();
31
+ this.scene.background = new THREE.Color(0x87CEEB); // Sky blue
32
+
33
+ // Create camera
34
+ this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
35
+ this.camera.position.set(0, 1.6, 0);
36
+
37
+ // Create renderer
38
+ this.renderer = new THREE.WebGLRenderer({ antialias: true });
39
+ this.renderer.setSize(window.innerWidth, window.innerHeight);
40
+ this.renderer.shadowMap.enabled = true;
41
+ this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
42
+
43
+ // Add renderer to DOM
44
+ document.getElementById('gameContainer').appendChild(this.renderer.domElement);
45
+
46
+ this.updateLoadingProgress(30, 'Setting up lighting...');
47
+ await this.setupLighting();
48
+
49
+ this.updateLoadingProgress(50, 'Creating world geometry...');
50
+ await this.createWorld();
51
+
52
+ this.updateLoadingProgress(70, 'Adding interactive objects...');
53
+ await this.addInteractiveObjects();
54
+
55
+ this.updateLoadingProgress(90, 'Setting up controls...');
56
+ this.setupControls();
57
+
58
+ this.updateLoadingProgress(100, 'Ready!');
59
+
60
+ // Show start screen after a brief delay
61
+ setTimeout(() => {
62
+ document.getElementById('loadingScreen').style.display = 'none';
63
+ document.getElementById('startScreen').style.display = 'flex';
64
+ }, 500);
65
+
66
+ // Start animation loop
67
+ this.animate();
68
+
69
+ // Handle window resize
70
+ window.addEventListener('resize', () => this.onWindowResize());
71
+ }
72
+
73
+ updateLoadingProgress(percent, text) {
74
+ document.getElementById('progressBar').style.width = percent + '%';
75
+ document.getElementById('loadingText').textContent = text;
76
+ }
77
+
78
+ async setupLighting() {
79
+ // Ambient light
80
+ const ambientLight = new THREE.AmbientLight(0x404040, 0.6);
81
+ this.scene.add(ambientLight);
82
+
83
+ // Directional light (sun)
84
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
85
+ directionalLight.position.set(50, 50, 50);
86
+ directionalLight.castShadow = true;
87
+ directionalLight.shadow.mapSize.width = 2048;
88
+ directionalLight.shadow.mapSize.height = 2048;
89
+ directionalLight.shadow.camera.near = 0.5;
90
+ directionalLight.shadow.camera.far = 500;
91
+ directionalLight.shadow.camera.left = -100;
92
+ directionalLight.shadow.camera.right = 100;
93
+ directionalLight.shadow.camera.top = 100;
94
+ directionalLight.shadow.camera.bottom = -100;
95
+ this.scene.add(directionalLight);
96
+
97
+ // Hemisphere light for more natural outdoor lighting
98
+ const hemisphereLight = new THREE.HemisphereLight(0x87CEEB, 0x8B4513, 0.4);
99
+ this.scene.add(hemisphereLight);
100
+ }
101
+
102
+ async createWorld() {
103
+ // Create ground
104
+ const groundGeometry = new THREE.PlaneGeometry(100, 100);
105
+ const groundMaterial = new THREE.MeshLambertMaterial({
106
+ color: 0x7CFC00, // Lawn green
107
+ side: THREE.DoubleSide
108
+ });
109
+ const ground = new THREE.Mesh(groundGeometry, groundMaterial);
110
+ ground.rotation.x = -Math.PI / 2;
111
+ ground.receiveShadow = true;
112
+ this.scene.add(ground);
113
+
114
+ // Add some grass texture variation
115
+ const grassTexture = new THREE.MeshLambertMaterial({
116
+ color: 0x32CD32, // Lime green
117
+ side: THREE.DoubleSide
118
+ });
119
+
120
+ for (let i = 0; i < 200; i++) {
121
+ const grassBlade = new THREE.Mesh(
122
+ new THREE.PlaneGeometry(0.1, 0.5),
123
+ grassTexture
124
+ );
125
+ grassBlade.position.set(
126
+ Math.random() * 80 - 40,
127
+ 0.25,
128
+ Math.random() * 80 - 40
129
+ );
130
+ grassBlade.rotation.x = -Math.PI / 2;
131
+ grassBlade.rotation.z = Math.random() * Math.PI;
132
+ this.scene.add(grassBlade);
133
+ }
134
+
135
+ // Create trees
136
+ for (let i = 0; i < 15; i++) {
137
+ this.createTree(
138
+ Math.random() * 70 - 35,
139
+ Math.random() * 70 - 35
140
+ );
141
+ }
142
+
143
+ // Create buildings
144
+ this.createBuilding(-15, 0, -15, 8, 12, 8, 0x888888);
145
+ this.createBuilding(15, 0, 15, 6, 8, 6, 0x666666);
146
+ this.createBuilding(-15, 0, 15, 5, 6, 5, 0x777777);
147
+
148
+ // Create a central fountain
149
+ this.createFountain(0, 0, 0);
150
+
151
+ // Create some rocks
152
+ for (let i = 0; i < 10; i++) {
153
+ this.createRock(
154
+ Math.random() * 60 - 30,
155
+ Math.random() * 60 - 30
156
+ );
157
+ }
158
+ }
159
+
160
+ createTree(x, z) {
161
+ // Tree trunk
162
+ const trunkGeometry = new THREE.CylinderGeometry(0.3, 0.4, 4);
163
+ const trunkMaterial = new THREE.MeshLambertMaterial({ color: 0x8B4513 });
164
+ const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
165
+ trunk.position.set(x, 2, z);
166
+ trunk.castShadow = true;
167
+ this.scene.add(trunk);
168
+
169
+ // Tree leaves
170
+ const leavesGeometry = new THREE.SphereGeometry(2);
171
+ const leavesMaterial = new THREE.MeshLambertMaterial({ color: 0x228B22 });
172
+ const leaves = new THREE.Mesh(leavesGeometry, leavesMaterial);
173
+ leaves.position.set(x, 5, z);
174
+ leaves.castShadow = true;
175
+ this.scene.add(leaves);
176
+ }
177
+
178
+ createBuilding(x, y, z, width, height, depth, color) {
179
+ const geometry = new THREE.BoxGeometry(width, height, depth);
180
+ const material = new THREE.MeshLambertMaterial({ color: color });
181
+ const building = new THREE.Mesh(geometry, material);
182
+ building.position.set(x, height / 2, z);
183
+ building.castShadow = true;
184
+ building.receiveShadow = true;
185
+ this.scene.add(building);
186
+
187
+ // Add windows
188
+ const windowMaterial = new THREE.MeshLambertMaterial({ color: 0x87CEEB });
189
+ for (let i = 0; i < 3; i++) {
190
+ for (let j = 0; j < 2; j++) {
191
+ const window = new THREE.Mesh(
192
+ new THREE.PlaneGeometry(0.8, 0.8),
193
+ windowMaterial
194
+ );
195
+ window.position.set(
196
+ x + (j - 0.5) * (width - 1),
197
+ y + 2 + i * 2.5,
198
+ z + depth / 2 + 0.1
199
+ );
200
+ window.rotation.y = Math.PI;
201
+ this.scene.add(window);
202
+ }
203
+ }
204
+ }
205
+
206
+ createFountain(x, y, z) {
207
+ // Fountain base
208
+ const baseGeometry = new THREE.CylinderGeometry(3, 3, 0.5, 32);
209
+ const baseMaterial = new THREE.MeshLambertMaterial({ color: 0xCCCCCC });
210
+ const base = new THREE.Mesh(baseGeometry, baseMaterial);
211
+ base.position.set(x, 0.25, z);
212
+ base.receiveShadow = true;
213
+ this.scene.add(base);
214
+
215
+ // Fountain center
216
+ const centerGeometry = new THREE.CylinderGeometry(1, 1.2, 2, 32);
217
+ const centerMaterial = new THREE.MeshLambertMaterial({ color: 0xDDDDDD });
218
+ const center = new THREE.Mesh(centerGeometry, centerMaterial);
219
+ center.position.set(x, 1.5, z);
220
+ center.castShadow = true;
221
+ this.scene.add(center);
222
+
223
+ // Water (animated)
224
+ const waterGeometry = new THREE.CylinderGeometry(1.2, 1.2, 0.2, 32);
225
+ const waterMaterial = new THREE.MeshLambertMaterial({
226
+ color: 0x4F94CD,
227
+ transparent: true,
228
+ opacity: 0.7
229
+ });
230
+ const water = new THREE.Mesh(waterGeometry, waterMaterial);
231
+ water.position.set(x, 1.1, z);
232
+ water.userData = { type: 'fountain', animate: true };
233
+ this.scene.add(water);
234
+ this.interactiveObjects.push(water);
235
+ }
236
+
237
+ createRock(x, z) {
238
+ const geometry = new THREE.SphereGeometry(0.5 + Math.random() * 0.5, 6, 6);
239
+ const material = new THREE.MeshLambertMaterial({ color: 0x696969 });
240
+ const rock = new THREE.Mesh(geometry, material);
241
+ rock.position.set(x, 0.5, z);
242
+ rock.rotation.set(
243
+ Math.random() * Math.PI,
244
+ Math.random() * Math.PI,
245
+ Math.random() * Math.PI
246
+ );
247
+ rock.castShadow = true;
248
+ this.scene.add(rock);
249
+ }
250
+
251
+ async addInteractiveObjects() {
252
+ // Create interactive squirrel NPC
253
+ this.createSquirrel(10, 0, 0);
254
+
255
+ // Create treasure chest
256
+ this.createTreasureChest(-10, 0, 10);
257
+
258
+ // Create signpost
259
+ this.createSignpost(15, 0, -15);
260
+ }
261
+
262
+ createSquirrel(x, y, z) {
263
+ // Squirrel body
264
+ const bodyGeometry = new THREE.SphereGeometry(0.4, 16, 16);
265
+ const bodyMaterial = new THREE.MeshLambertMaterial({ color: 0xFF8C00 });
266
+ const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
267
+ body.position.set(x, y + 0.4, z);
268
+
269
+ // Squirrel head
270
+ const headGeometry = new THREE.SphereGeometry(0.3, 16, 16);
271
+ const head = new THREE.Mesh(headGeometry, bodyMaterial);
272
+ head.position.set(x, y + 0.8, z + 0.3);
273
+
274
+ // Squirrel tail
275
+ const tailGeometry = new THREE.SphereGeometry(0.25, 16, 16);
276
+ const tail = new THREE.Mesh(tailGeometry, bodyMaterial);
277
+ tail.position.set(x, y + 0.4, z - 0.5);
278
+ tail.scale.set(1.5, 0.8, 2);
279
+
280
+ const squirrel = new THREE.Group();
281
+ squirrel.add(body);
282
+ squirrel.add(head);
283
+ squirrel.add(tail);
284
+ squirrel.userData = {
285
+ type: 'squirrel',
286
+ interactive: true,
287
+ message: "Hello! I'm your friendly squirrel guide. Explore the playground and find hidden treasures!"
288
+ };
289
+ squirrel.castShadow = true;
290
+
291
+ this.scene.add(squirrel);
292
+ this.interactiveObjects.push(squirrel);
293
+ }
294
+
295
+ createTreasureChest(x, y, z) {
296
+ const chestGeometry = new THREE.BoxGeometry(1.5, 0.8, 1);
297
+ const chestMaterial = new THREE.MeshLambertMaterial({ color: 0xDAA520 });
script.js ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Main JavaScript for SquirrelView 3D Sandbox Explorer
2
+
3
+ // Initialize Feather Icons
4
+ document.addEventListener('DOMContentLoaded', function() {
5
+ feather.replace();
6
+
7
+ // Add smooth scrolling to all links
8
+ document.querySelectorAll('a[href^="#"]').forEach(anchor => {
9
+ anchor.addEventListener('click', function (e) {
10
+ e.preventDefault();
11
+ document.querySelector(this.getAttribute('href')).scrollIntoView({
12
+ behavior: 'smooth'
13
+ });
14
+ });
15
+ });
16
+
17
+ // Add animation to feature cards on scroll
18
+ const observerOptions = {
19
+ threshold: 0.1,
20
+ rootMargin: '0px 0px -50px 0px'
21
+ };
22
+
23
+ const observer = new IntersectionObserver((entries) => {
24
+ entries.forEach(entry => {
25
+ if (entry.isIntersecting) {
26
+ entry.target.classList.add('fade-in');
27
+ }
28
+ });
29
+ }, observerOptions);
30
+
31
+ document.querySelectorAll('.feature-card').forEach(card => {
32
+ observer.observe(card);
33
+ });
34
+
35
+ // Download button functionality
36
+ const downloadButton = document.querySelector('button:contains("Download Full Script")');
37
+ if (downloadButton) {
38
+ downloadButton.addEventListener('click', function() {
39
+ // Create and trigger download of the Python script
40
+ const pythonScript = `import ursina as u
41
+ from ursina.prefabs.first_person_controller import FirstPersonController
42
+ import os
43
+ from ursina import scene
44
+
45
+ class SquirrelViewSandbox:
46
+ def __init__(self):
47
+ # Initialize application
48
+ self.app = u.Ursina()
49
+
50
+ # Window settings
51
+ u.window.title = "SquirrelView 3D Sandbox Explorer"
52
+ u.window.borderless = False
53
+ u.window.fullscreen = False
54
+
55
+ # World setup
56
+ self.setup_world()
57
+ self.setup_player()
58
+ self.setup_ui()
59
+ self.setup_controller()
60
+
61
+ def setup_world(self):
62
+ # Create ground
63
+ self.ground = u.Entity(
64
+ model='plane',
65
+ scale=(200, 1, 200),
66
+ texture='white_cube',
67
+ texture_scale=(40, 40),
68
+ collider='box'
69
+ )
70
+
71
+ # Sky
72
+ self.sky = u.Sky()
73
+
74
+ # Initial environment objects
75
+ self.create_environment()
76
+
77
+ def create_environment(self):
78
+ # Trees
79
+ for i in range(20):
80
+ tree = u.Entity(
81
+ model='cube',
82
+ position=(u.random.uniform(-50, 50), 2, u.random.uniform(-50, 50)),
83
+ scale=(1, 4, 1),
84
+ color=u.color.brown
85
+ )
86
+
87
+ # Buildings
88
+ building_positions = [(-20, 0, -20), (20, 0, 20), (-20, 0, 20)]
89
+ for pos in building_positions:
90
+ building = u.Entity(
91
+ model='cube',
92
+ position=pos,
93
+ scale=(5, 8, 5),
94
+ color=u.color.gray
95
+ )
96
+
97
+ # Squirrel NPC
98
+ self.squirrel = u.Entity(
99
+ model='cube',
100
+ position=(10, 0.5, 0),
101
+ scale=(1, 1, 1),
102
+ color=u.color.orange,
103
+ collider='box'
104
+ )
105
+
106
+ def setup_player(self):
107
+ # Player controller
108
+ self.player = FirstPersonController()
109
+ self.player.speed = 8
110
+ self.player.jump_height = 2
111
+ self.player.cursor.visible = False
112
+
113
+ def setup_controller(self):
114
+ # PS4 controller mapping
115
+ self.controller_enabled = True
116
+
117
+ def setup_ui(self):
118
+ # HUD elements
119
+ self.hud = u.Entity(parent=u.camera.ui)
120
+
121
+ # Inventory panel (initially hidden)
122
+ self.inventory_panel = u.Entity(
123
+ parent=self.hud,
124
+ model='quad',
125
+ scale=(0.8, 0.6),
126
+ position=(0, 0, -1),
127
+ color=u.color.color(0, 0, 0, 0.8),
128
+ enabled=False
129
+ )
130
+
131
+ # Squirrel interaction dialog
132
+ self.dialog_box = u.Entity(
133
+ parent=self.hud,
134
+ model='quad',
135
+ scale=(0.6, 0.3),
136
+ position=(0, 0.2, -1),
137
+ color=u.color.color(0.1, 0.1, 0.1, 0.9),
138
+ enabled=False
139
+ )
140
+
141
+ def load_model(self, filepath):
142
+ # Supported formats
143
+ supported_formats = ['.glb', '.obj', '.stl']
144
+ file_ext = os.path.splitext(filepath)[1].lower()
145
+
146
+ if file_ext in supported_formats:
147
+ try:
148
+ model = u.Entity(
149
+ model=filepath,
150
+ position=self.player.position + self.player.forward * 3,
151
+ scale=1,
152
+ collider='mesh'
153
+ )
154
+ return model
155
+ except Exception as e:
156
+ print(f"Error loading model: {e}")
157
+ return None
158
+ else:
159
+ print(f"Unsupported format: {file_ext}")
160
+ return None
161
+
162
+ def update(self):
163
+ # Controller input handling
164
+ if self.controller_enabled:
165
+ self.handle_controller_input()
166
+
167
+ # Squirrel interaction check
168
+ self.check_squirrel_interaction()
169
+
170
+ def handle_controller_input(self):
171
+ # PS4 controller axis mapping
172
+ if u.held_keys['gamepad left stick x']:
173
+ self.player.x += u.time.dt * u.held_keys['gamepad left stick x'] * self.player.speed
174
+ if u.held_keys['gamepad left stick y']:
175
+ self.player.z += u.time.dt * u.held_keys['gamepad left stick y'] * self.player.speed
176
+
177
+ # Button mappings
178
+ if u.held_keys['gamepad a']:
179
+ self.jump()
180
+ if u.held_keys['gamepad x']:
181
+ self.toggle_inventory()
182
+
183
+ def check_squirrel_interaction(self):
184
+ # Check if player is near squirrel
185
+ distance = (self.player.position - self.squirrel.position).length()
186
+ if distance < 3:
187
+ self.show_dialog("Press X to open model loader!")
188
+ if u.held_keys['gamepad x'] or u.held_keys['e']:
189
+ self.open_model_loader()
190
+
191
+ def show_dialog(self, message):
192
+ self.dialog_box.enabled = True
193
+ # Add text to dialog box here
194
+
195
+ def open_model_loader(self):
196
+ # Implement file browser for model loading
197
+ pass
198
+
199
+ def toggle_inventory(self):
200
+ self.inventory_panel.enabled = not self.inventory_panel.enabled
201
+
202
+ def run(self):
203
+ self.app.run()
204
+
205
+ # Start the application
206
+ if __name__ == "__main__":
207
+ sandbox = SquirrelViewSandbox()
208
+ sandbox.run()`;
209
+
210
+ const blob = new Blob([pythonScript], { type: 'text/x-python' });
211
+ const url = URL.createObjectURL(blob);
212
+ const a = document.createElement('a');
213
+ a.href = url;
214
+ a.download = 'squirrelview_sandbox.py';
215
+ document.body.appendChild(a);
216
+ a.click();
217
+ document.body.removeChild(a);
218
+ URL.revokeObjectURL(url);
219
+
220
+ // Show success message
221
+ alert('Python script downloaded successfully!');
222
+ });
223
+ }
224
+
225
+ // Add loading animation to buttons
226
+ document.querySelectorAll('button').forEach(button => {
227
+ button.addEventListener('click', function() {
228
+ const originalText = this
style.css CHANGED
@@ -1,28 +1,86 @@
1
- body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  }
5
 
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
9
  }
10
 
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
  }
17
 
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
24
  }
25
 
26
- .card p:last-child {
27
- margin-bottom: 0;
 
28
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Custom styles for SquirrelView 3D Sandbox Explorer */
2
+
3
+ /* Smooth scrolling */
4
+ html {
5
+ scroll-behavior: smooth;
6
+ }
7
+
8
+ /* Custom gradient backgrounds */
9
+ .gradient-bg {
10
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
11
+ }
12
+
13
+ /* Code block styling */
14
+ pre code {
15
+ font-family: 'Courier New', monospace;
16
+ font-size: 0.9rem;
17
+ line-height: 1.4;
18
+ }
19
+
20
+ /* Custom scrollbar */
21
+ ::-webkit-scrollbar {
22
+ width: 8px;
23
+ }
24
+
25
+ ::-webkit-scrollbar-track {
26
+ background: #1f2937;
27
+ }
28
+
29
+ ::-webkit-scrollbar-thumb {
30
+ background: #4b5563;
31
+ border-radius: 4px;
32
  }
33
 
34
+ ::-webkit-scrollbar-thumb:hover {
35
+ background: #6b7280;
 
36
  }
37
 
38
+ /* Animation classes */
39
+ .fade-in {
40
+ animation: fadeIn 0.8s ease-in;
 
 
41
  }
42
 
43
+ @keyframes fadeIn {
44
+ from { opacity: 0; transform: translateY(20px); }
45
+ to { opacity: 1; transform: translateY(0); }
 
 
 
46
  }
47
 
48
+ /* Button hover effects */
49
+ .btn-hover {
50
+ transition: all 0.3s ease;
51
  }
52
+
53
+ .btn-hover:hover {
54
+ transform: translateY(-2px);
55
+ box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
56
+ }
57
+
58
+ /* Feature card animations */
59
+ .feature-card {
60
+ transition: all 0.3s ease;
61
+ }
62
+
63
+ .feature-card:hover {
64
+ transform: translateY(-5px);
65
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
66
+ }
67
+
68
+ /* Responsive text sizing */
69
+ @media (max-width: 768px) {
70
+ .responsive-text {
71
+ font-size: 0.875rem;
72
+ }
73
+ }
74
+
75
+ /* Loading animation */
76
+ .loading-dots::after {
77
+ content: '';
78
+ animation: dots 1.5s steps(5, end) infinite;
79
+ }
80
+
81
+ @keyframes dots {
82
+ 0%, 20% { content: '.'; }
83
+ 40% { content: '..'; }
84
+ 60% { content: '...'; }
85
+ 80%, 100% { content: ''; }
86
+ }