Skip to content

Commit 3edb00b

Browse files
authored
Add Examples Browser (#47)
1 parent 4a6fe68 commit 3edb00b

File tree

2 files changed

+287
-11
lines changed

2 files changed

+287
-11
lines changed

examples/index.html

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
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>PlayCanvas Web Components - Examples</title>
7+
<style>
8+
body {
9+
margin: 0;
10+
padding: 0;
11+
display: grid;
12+
grid-template-columns: 250px 1fr;
13+
height: 100vh;
14+
font-family: system-ui, -apple-system, sans-serif;
15+
overflow: hidden;
16+
}
17+
18+
.sidebar {
19+
background: #f5f5f5;
20+
padding: 20px;
21+
border-right: 1px solid #ddd;
22+
overflow-y: auto;
23+
}
24+
25+
.main {
26+
position: relative;
27+
overflow: hidden;
28+
}
29+
30+
#example-frame {
31+
width: 100%;
32+
height: 100%;
33+
border: none;
34+
display: block;
35+
}
36+
37+
#code-panel {
38+
position: absolute;
39+
top: 50%;
40+
left: 50%;
41+
transform: translate(-50%, -50%);
42+
width: 80%;
43+
height: 80%;
44+
background: rgba(0, 0, 0, 0.9);
45+
padding: 20px;
46+
overflow: auto;
47+
display: none;
48+
backdrop-filter: blur(2px);
49+
box-sizing: border-box;
50+
z-index: 2;
51+
}
52+
53+
#code-panel pre {
54+
margin: 0;
55+
white-space: pre-wrap;
56+
}
57+
58+
#code-panel code {
59+
font-family: 'Fira Code', Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
60+
font-size: 14px;
61+
}
62+
63+
.example-link {
64+
display: flex;
65+
align-items: center;
66+
justify-content: space-between;
67+
padding: 8px;
68+
color: #333;
69+
text-decoration: none;
70+
border-radius: 4px;
71+
}
72+
73+
.example-link:hover {
74+
background: #ffe0cc;
75+
}
76+
77+
.example-link.active {
78+
background: #ff8533;
79+
color: white;
80+
}
81+
82+
.open-in-new {
83+
opacity: 0.5;
84+
padding: 4px;
85+
border-radius: 4px;
86+
}
87+
88+
.open-in-new:hover {
89+
opacity: 1;
90+
background: rgba(0, 0, 0, 0.1);
91+
}
92+
93+
.example-link.active .open-in-new {
94+
filter: brightness(2);
95+
}
96+
97+
pre {
98+
margin: 0;
99+
white-space: pre-wrap;
100+
}
101+
102+
.controls {
103+
padding: 10px;
104+
position: absolute;
105+
top: 0;
106+
right: 0;
107+
z-index: 1;
108+
}
109+
110+
/* Webkit (Chrome, Safari, newer versions of Opera) */
111+
::-webkit-scrollbar {
112+
width: 10px;
113+
height: 10px;
114+
}
115+
116+
::-webkit-scrollbar-track {
117+
background: rgba(0, 0, 0, 0.1);
118+
}
119+
120+
::-webkit-scrollbar-thumb {
121+
background: rgba(0, 0, 0, 0.3);
122+
border-radius: 5px;
123+
}
124+
125+
::-webkit-scrollbar-thumb:hover {
126+
background: rgba(0, 0, 0, 0.4);
127+
}
128+
129+
/* For Firefox */
130+
* {
131+
scrollbar-width: thin;
132+
scrollbar-color: rgba(0, 0, 0, 0.3) rgba(0, 0, 0, 0.1);
133+
}
134+
135+
/* Dark scrollbars for code panel */
136+
#code-panel::-webkit-scrollbar-track {
137+
background: rgba(255, 255, 255, 0.1);
138+
}
139+
140+
#code-panel::-webkit-scrollbar-thumb {
141+
background: rgba(255, 255, 255, 0.3);
142+
}
143+
144+
#code-panel::-webkit-scrollbar-thumb:hover {
145+
background: rgba(255, 255, 255, 0.4);
146+
}
147+
148+
#code-panel {
149+
scrollbar-color: rgba(255, 255, 255, 0.3) rgba(255, 255, 255, 0.1);
150+
}
151+
152+
#overlay {
153+
position: fixed;
154+
top: 0;
155+
left: 0;
156+
right: 0;
157+
bottom: 0;
158+
display: none;
159+
}
160+
</style>
161+
<!-- Add Prism CSS and JS -->
162+
<link href="https://cdn.jsdelivr.net/npm/[email protected]/themes/prism-tomorrow.min.css" rel="stylesheet" />
163+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/prism.min.js"></script>
164+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/components/prism-javascript.min.js"></script>
165+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/components/prism-markup.min.js"></script>
166+
</head>
167+
<body>
168+
<div class="sidebar">
169+
<h2>Web Components Examples</h2>
170+
<div id="example-list"></div>
171+
</div>
172+
<div class="main">
173+
<div class="controls">
174+
<button onclick="toggleCode()">View Source</button>
175+
</div>
176+
<iframe id="example-frame"></iframe>
177+
<div id="code-panel">
178+
<pre><code id="source-code" class="language-html"></code></pre>
179+
</div>
180+
</div>
181+
<div id="overlay"></div>
182+
<script>
183+
const examples = [
184+
{ name: 'Animation', path: 'animation.html' },
185+
{ name: 'GLB Loader', path: 'glb.html' },
186+
{ name: 'Physics', path: 'physics.html' },
187+
{ name: 'Positional Sound', path: 'positional-sound.html' },
188+
{ name: 'Shapes', path: 'shapes.html' },
189+
{ name: 'Spinning Cube', path: 'spinning-cube.html' },
190+
{ name: 'Sound', path: 'sound.html' },
191+
{ name: 'Text Demo', path: 'text.html' },
192+
{ name: '3D Gaussian Splat', path: 'splat.html' }
193+
];
194+
195+
const exampleList = document.getElementById('example-list');
196+
const frame = document.getElementById('example-frame');
197+
const codePanel = document.getElementById('code-panel');
198+
const sourceCode = document.getElementById('source-code');
199+
200+
// Create example links
201+
examples.forEach(example => {
202+
const link = document.createElement('a');
203+
link.href = '#' + example.path;
204+
link.className = 'example-link';
205+
206+
// Add example name span
207+
const nameSpan = document.createElement('span');
208+
nameSpan.textContent = example.name;
209+
link.appendChild(nameSpan);
210+
211+
// Add "open in new tab" icon
212+
const openInNew = document.createElement('a');
213+
openInNew.href = example.path;
214+
openInNew.target = '_blank';
215+
openInNew.className = 'open-in-new';
216+
openInNew.innerHTML = '↗️';
217+
openInNew.title = 'Open in new tab';
218+
openInNew.onclick = (e) => e.stopPropagation();
219+
link.appendChild(openInNew);
220+
221+
link.onclick = (e) => {
222+
if (e.target !== openInNew) { // Don't load in iframe if clicking the "open in new" icon
223+
e.preventDefault();
224+
loadExample(example.path);
225+
document.querySelectorAll('.example-link').forEach(l => l.classList.remove('active'));
226+
link.classList.add('active');
227+
}
228+
};
229+
230+
exampleList.appendChild(link);
231+
});
232+
233+
async function loadExample(path) {
234+
frame.src = path;
235+
const response = await fetch(path);
236+
const code = await response.text();
237+
sourceCode.textContent = code;
238+
Prism.highlightElement(sourceCode);
239+
codePanel.style.display = 'none';
240+
}
241+
242+
function toggleCode() {
243+
const isVisible = codePanel.style.display === 'block';
244+
codePanel.style.display = isVisible ? 'none' : 'block';
245+
document.getElementById('overlay').style.display = isVisible ? 'none' : 'block';
246+
}
247+
248+
document.getElementById('overlay').addEventListener('click', () => {
249+
codePanel.style.display = 'none';
250+
document.getElementById('overlay').style.display = 'none';
251+
});
252+
253+
// Add escape key handler
254+
document.addEventListener('keydown', (e) => {
255+
if (e.key === 'Escape' && codePanel.style.display === 'block') {
256+
codePanel.style.display = 'none';
257+
}
258+
});
259+
260+
// Add click handler to close panel when clicking outside
261+
document.querySelector('.main').addEventListener('click', (e) => {
262+
if (codePanel.style.display === 'block' &&
263+
!codePanel.contains(e.target) &&
264+
!e.target.closest('button')) { // Better button check
265+
codePanel.style.display = 'none';
266+
}
267+
});
268+
269+
// Alternative approach: handle clicks on specific areas
270+
document.querySelector('.main').addEventListener('click', (e) => {
271+
const isButton = e.target.closest('button');
272+
const isCodePanel = e.target.closest('#code-panel');
273+
274+
if (codePanel.style.display === 'block' && !isButton && !isCodePanel) {
275+
codePanel.style.display = 'none';
276+
}
277+
});
278+
279+
// Load first example by default
280+
if (examples.length > 0) {
281+
loadExample(examples[0].path);
282+
exampleList.firstChild.classList.add('active');
283+
}
284+
</script>
285+
</body>
286+
</html>

examples/spinning-cube.html

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,7 @@
1616
</head>
1717
<body>
1818
<pc-app>
19-
<script type="module">
20-
import { registerScript, Script } from 'playcanvas';
21-
22-
class Rotate extends Script {
23-
update(dt) {
24-
this.entity.rotate(10 * dt, 20 * dt, 30 * dt);
25-
}
26-
}
27-
28-
registerScript(Rotate, 'rotate');
29-
</script>
19+
<pc-asset id="rotate" src="scripts/rotate.mjs" preload></pc-asset>
3020
<!-- Scene -->
3121
<pc-scene>
3222
<!-- Camera -->

0 commit comments

Comments
 (0)