Skip to content

Commit de84acf

Browse files
Add iframe.html for PythonExtra demo with 3D cube
1 parent 4758c71 commit de84acf

1 file changed

Lines changed: 280 additions & 0 deletions

File tree

iframe.html

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
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>PythonExtra Demo: Cyberspace</title>
7+
<style>
8+
body {
9+
background-color: #222;
10+
display: flex;
11+
justify-content: center;
12+
align-items: center;
13+
height: 100vh;
14+
margin: 0;
15+
font-family: monospace;
16+
color: #888;
17+
}
18+
#calculator-bezel {
19+
background-color: #e0e0e0;
20+
padding: 20px;
21+
border-radius: 15px;
22+
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
23+
display: flex;
24+
flex-direction: column;
25+
align-items: center;
26+
}
27+
canvas {
28+
background-color: #000;
29+
border: 2px solid #999;
30+
/* Ensures crisp scaling on high-DPI screens */
31+
image-rendering: pixelated;
32+
image-rendering: crisp-edges;
33+
width: 320px;
34+
height: 528px;
35+
box-shadow: inset 0 0 10px rgba(0,0,0,0.8);
36+
}
37+
.controls {
38+
margin-top: 10px;
39+
font-size: 12px;
40+
}
41+
</style>
42+
</head>
43+
<body>
44+
45+
<div id="calculator-bezel">
46+
<!-- Canvas size matches calculator resolution exactly -->
47+
<canvas id="screen" width="320" height="528"></canvas>
48+
<div class="controls">PythonExtra JS Simulator • 320x528</div>
49+
</div>
50+
51+
<script>
52+
/**
53+
* GINT / PYTHONEXTRA SHIM FOR JS CANVAS
54+
* Mimics the environment of the calculator
55+
*/
56+
const canvas = document.getElementById('screen');
57+
const ctx = canvas.getContext('2d', { alpha: false }); // Optimize for no transparency
58+
const DWIDTH = 320;
59+
const DHEIGHT = 528;
60+
61+
// Configuration from Python script
62+
const WIDTH = DWIDTH;
63+
const HEIGHT = DHEIGHT;
64+
const CX = Math.floor(WIDTH / 2);
65+
const CY = Math.floor(HEIGHT / 2);
66+
67+
// Disable smoothing for pixel-perfect rendering
68+
ctx.imageSmoothingEnabled = false;
69+
70+
// Color helper: Maps 0-31 range (RGB555) to 0-255 CSS RGB
71+
function C_RGB(r, g, b) {
72+
const R = Math.floor(r * 255 / 31);
73+
const G = Math.floor(g * 255 / 31);
74+
const B = Math.floor(b * 255 / 31);
75+
return `rgb(${R}, ${G}, ${B})`;
76+
}
77+
78+
const C_WHITE = C_RGB(31, 31, 31);
79+
const C_BG = "#000000";
80+
const C_NONE = null;
81+
82+
// Drawing Primitives - Integers only for pixel alignment
83+
function dclear(color) {
84+
ctx.fillStyle = color;
85+
ctx.fillRect(0, 0, WIDTH, HEIGHT);
86+
}
87+
88+
function dline(x1, y1, x2, y2, color) {
89+
if (!color) return;
90+
ctx.strokeStyle = color;
91+
ctx.lineWidth = 1; // 1px lines for precision
92+
ctx.beginPath();
93+
// Math.floor ensures we hit exact pixels
94+
ctx.moveTo(Math.floor(x1) + 0.5, Math.floor(y1) + 0.5);
95+
ctx.lineTo(Math.floor(x2) + 0.5, Math.floor(y2) + 0.5);
96+
ctx.stroke();
97+
}
98+
99+
function drect(x1, y1, x2, y2, color) {
100+
if (!color) return;
101+
ctx.fillStyle = color;
102+
const x = Math.min(x1, x2) | 0;
103+
const y = Math.min(y1, y2) | 0;
104+
const w = (Math.abs(x2 - x1) + 1) | 0;
105+
const h = (Math.abs(y2 - y1) + 1) | 0;
106+
ctx.fillRect(x, y, w, h);
107+
}
108+
109+
// Text handling
110+
const DTEXT_LEFT = 'left';
111+
const DTEXT_CENTER = 'center';
112+
const DTEXT_RIGHT = 'right';
113+
const DTEXT_TOP = 'top';
114+
const DTEXT_BOTTOM = 'bottom';
115+
116+
function dtext(x, y, color, text) {
117+
if (!color) return;
118+
ctx.fillStyle = color;
119+
ctx.font = '16px "Courier New", monospace';
120+
ctx.textAlign = 'left';
121+
ctx.textBaseline = 'top';
122+
ctx.fillText(text, Math.floor(x), Math.floor(y));
123+
}
124+
125+
function dtext_opt(x, y, fg, bg, halign, valign, text) {
126+
ctx.font = '16px "Courier New", monospace';
127+
ctx.textAlign = halign;
128+
129+
if (valign === DTEXT_TOP) ctx.textBaseline = 'top';
130+
else if (valign === DTEXT_BOTTOM) ctx.textBaseline = 'bottom';
131+
else ctx.textBaseline = 'middle';
132+
133+
ctx.fillStyle = fg;
134+
ctx.fillText(text, Math.floor(x), Math.floor(y));
135+
}
136+
137+
/**
138+
* MAIN DEMO LOGIC
139+
*/
140+
141+
// 3D Cube Data
142+
const VERTICES = [
143+
[-1, -1, -1], [1, -1, -1], [1, 1, -1], [-1, 1, -1],
144+
[-1, -1, 1], [1, -1, 1], [1, 1, 1], [-1, 1, 1]
145+
];
146+
147+
const EDGES = [
148+
[0,1], [1,2], [2,3], [3,0],
149+
[4,5], [5,6], [6,7], [7,4],
150+
[0,4], [1,5], [2,6], [3,7]
151+
];
152+
153+
// State variables
154+
let angle_x = 0.0;
155+
let angle_y = 0.0;
156+
let angle_z = 0.0;
157+
const scale_base = 80;
158+
159+
// Scroller
160+
const msg = " WELCOME TO PYTHONEXTRA ... DEMO SCENE EFFECT ... GINT GRAPHICS LIBRARY ... 3D CUBE RENDERING ... ";
161+
let msg_x = WIDTH;
162+
const text_width = msg.length * 10;
163+
164+
function rotate_point(x, y, z, ax, ay, az) {
165+
let s, c;
166+
// Rotate X
167+
if (ax !== 0) {
168+
s = Math.sin(ax); c = Math.cos(ax);
169+
let ny = y * c - z * s;
170+
let nz = y * s + z * c;
171+
y = ny; z = nz;
172+
}
173+
// Rotate Y
174+
if (ay !== 0) {
175+
s = Math.sin(ay); c = Math.cos(ay);
176+
let nx = x * c - z * s;
177+
let nz = x * s + z * c;
178+
x = nx; z = nz;
179+
}
180+
// Rotate Z
181+
if (az !== 0) {
182+
s = Math.sin(az); c = Math.cos(az);
183+
let nx = x * c - y * s;
184+
let ny = x * s + y * c;
185+
x = nx; y = ny;
186+
}
187+
return {x, y, z};
188+
}
189+
190+
// Animation Loop Control
191+
const FPS = 40;
192+
const FRAME_INTERVAL = 1000 / FPS;
193+
let lastFrameTime = 0;
194+
const startTime = Date.now();
195+
196+
function loop(currentTime) {
197+
requestAnimationFrame(loop);
198+
199+
// FPS Limiter
200+
const elapsed = currentTime - lastFrameTime;
201+
if (elapsed < FRAME_INTERVAL) return;
202+
203+
// Adjust lastFrameTime to target interval (avoids drift)
204+
lastFrameTime = currentTime - (elapsed % FRAME_INTERVAL);
205+
206+
// Logic time relative to start
207+
const t = (Date.now() - startTime) / 1000;
208+
209+
// Update Physics
210+
angle_x += 0.04;
211+
angle_y += 0.02;
212+
angle_z += 0.01;
213+
214+
const y_offset = Math.sin(t * 2.5) * 60;
215+
216+
// Colors
217+
const r = Math.floor((Math.sin(t * 3) + 1) * 15.5);
218+
const g = Math.floor((Math.sin(t * 3 + 2) + 1) * 15.5);
219+
const b = Math.floor((Math.sin(t * 3 + 4) + 1) * 15.5);
220+
const col_wire = C_RGB(r, g, b);
221+
222+
// Draw
223+
dclear(C_BG);
224+
225+
// Background Grid
226+
const grid_col = C_RGB(6, 6, 6);
227+
const grid_speed = (t * 50) % 40;
228+
229+
for (let i = 0; i < HEIGHT / 2; i += 40) {
230+
const y_pos = HEIGHT - i + grid_speed;
231+
if (y_pos < HEIGHT) {
232+
dline(0, y_pos, WIDTH, y_pos, grid_col);
233+
}
234+
}
235+
for (let i = -200; i < WIDTH + 200; i += 80) {
236+
dline(i, HEIGHT, CX, CY, grid_col);
237+
}
238+
239+
// 3D Cube
240+
const projected_points = [];
241+
242+
for (let v of VERTICES) {
243+
const p = rotate_point(v[0], v[1], v[2], angle_x, angle_y, angle_z);
244+
const dist = 4;
245+
const z_factor = 1 / (dist - p.z);
246+
247+
// Floor coordinates for pixel perfection
248+
const px = Math.floor(p.x * scale_base * z_factor + CX);
249+
const py = Math.floor(p.y * scale_base * z_factor + CY + y_offset);
250+
251+
projected_points.push({x: px, y: py});
252+
}
253+
254+
for (let edge of EDGES) {
255+
const p1 = projected_points[edge[0]];
256+
const p2 = projected_points[edge[1]];
257+
dline(p1.x, p1.y, p2.x, p2.y, col_wire);
258+
}
259+
260+
// Scroller
261+
drect(0, HEIGHT - 30, WIDTH, HEIGHT, C_RGB(0, 0, 10));
262+
dline(0, HEIGHT - 30, WIDTH, HEIGHT - 30, C_WHITE);
263+
dtext(Math.floor(msg_x), HEIGHT - 24, C_WHITE, msg);
264+
265+
msg_x -= 3;
266+
if (msg_x < -text_width) {
267+
msg_x = WIDTH;
268+
}
269+
270+
// HUD
271+
dtext_opt(CX, 10, C_WHITE, null, DTEXT_CENTER, DTEXT_TOP, "PythonExtra Demo");
272+
dtext_opt(CX, 25, col_wire, null, DTEXT_CENTER, DTEXT_TOP, "[EXIT] to Quit");
273+
}
274+
275+
// Initialize loop
276+
loop(0);
277+
278+
</script>
279+
</body>
280+
</html>

0 commit comments

Comments
 (0)