Skip to content

Commit 81500fe

Browse files
committed
Example apps refinement.
1 parent d6bf860 commit 81500fe

24 files changed

Lines changed: 976 additions & 666 deletions

File tree

docs/example-apps/bouncing-ball/game.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
Bouncing Ball - PyGame-CE demo for PyScript.
33
44
Based on the PyGame-CE quickstart tutorial.
5+
6+
Note the use of `await asyncio.sleep()` in place of `pygame.time.Clock()`
7+
to yield to the event loop and keep the browser responsive.
58
"""
69
import asyncio
710
import sys
@@ -21,14 +24,13 @@
2124
for event in pygame.event.get():
2225
if event.type == pygame.QUIT:
2326
sys.exit()
24-
2527
ballrect = ballrect.move(speed)
2628
if ballrect.left < 0 or ballrect.right > width:
2729
speed[0] = -speed[0]
2830
if ballrect.top < 0 or ballrect.bottom > height:
2931
speed[1] = -speed[1]
30-
3132
screen.fill(black)
3233
screen.blit(ball, ballrect)
3334
pygame.display.flip()
35+
# Needed to yield to the event loop to keep the browser responsive.
3436
await asyncio.sleep(1/60)
Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
# Bouncing Ball
22

3+
[Run the app](index.html) |
4+
[View the code on GitHub](https://github.com/pyscript/docs/tree/main/docs/example-apps/bouncing-ball)
5+
36
A simple PyGame-CE demonstration running in the browser with PyScript.
47
Based on the
58
[PyGame-CE quickstart tutorial](https://pyga.me/docs/tutorials/en/intro-to-pygame.html).
69

7-
## What it shows
10+
## What it demonstrates
811

912
- Running PyGame-CE in the browser with the `py-game` script type.
1013
- Using `await asyncio.sleep()` for frame timing in the browser.
@@ -20,21 +23,4 @@ yields control to the browser with `await asyncio.sleep(1/60)`.
2023

2124
The `await` at the top level works because PyScript provides an async
2225
context. This wouldn't run in standard Python without wrapping in an
23-
async function.
24-
25-
## Required files
26-
27-
You'll need to download `intro_ball.webp` from the PyGame-CE repository:
28-
https://raw.githubusercontent.com/pygame-community/pygame-ce/80fe4cb9f89aef96f586f68d269687572e7843f6/docs/reST/tutorials/assets/intro_ball.gif
29-
30-
Place it in the same directory as the other files.
31-
32-
## Running locally
33-
34-
Serve the files with any web server:
35-
36-
```sh
37-
python -m http.server 8000
38-
```
39-
40-
Then visit `http://localhost:8000/` in your browser.
26+
async function.

docs/example-apps/colour-picker/info.md

Lines changed: 19 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,28 @@
11
# Interactive Colour Picker
22

3+
[Run the app](index.html) |
4+
[View the code on GitHub](https://github.com/pyscript/docs/tree/main/docs/example-apps/colour-picker)
5+
36
A colour picker application demonstrating various event handling
47
patterns in PyScript.
58

69
## What it demonstrates
710

8-
**Multiple event types:**
9-
- `input` events - RGB sliders update in real-time.
10-
- `change` events - Number inputs and hex input.
11-
- `click` events - Preset buttons and history colours.
12-
13-
**Stacked decorators:**
14-
- Single function handling multiple sliders with `@when` stacked three
15-
times.
16-
17-
**Custom events:**
18-
- `colour_changed` Event for decoupling colour updates from history
19-
management.
20-
- Shows how to separate concerns in your application.
21-
22-
**Working with form inputs:**
23-
- Range sliders, number inputs, text inputs.
24-
- Synchronising values across different input types.
25-
- Validating and clamping values.
26-
27-
**Dynamic UI updates:**
28-
- Updating display colour.
29-
- Maintaining colour history.
30-
- Creating history elements dynamically.
11+
* Multiple event types with `input` events (RGB sliders update in real-time),
12+
`change` events (number inputs and hex input) and `click` events (preset
13+
buttons and history colours).
14+
* Stacked decorators with a single function handling multiple sliders with
15+
`@when` stacked three times.
16+
* Custom events via the `colour_changed` Event for decoupling colour updates
17+
from app history and to show how to separate concerns in your application.
18+
* Working with form inputs of different types:
19+
- Range sliders, number inputs, text inputs.
20+
- Synchronising values across different input types.
21+
- Validating and clamping values.
22+
* Dynamic UI updates:
23+
- Updating display colour.
24+
- Maintaining colour history.
25+
- Creating history elements dynamically.
3126

3227
## Features
3328

@@ -44,7 +39,7 @@ patterns in PyScript.
4439
- `index.html` - Page structure and styling.
4540
- `main.py` - Event handling logic demonstrating various patterns.
4641

47-
## Key patterns demonstrated
42+
## How it works
4843

4944
### Stacking decorators
5045

@@ -82,13 +77,3 @@ def handle_slider_change(event):
8277
# Update display.
8378
update_display(value)
8479
```
85-
86-
## Running locally
87-
88-
Serve these files from a web server:
89-
90-
```bash
91-
python3 -m http.server
92-
```
93-
94-
Then open http://localhost:8000 in your browser.

docs/example-apps/colour-picker/main.py

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,32 @@
22
Interactive Colour Picker - demonstrating event handling in PyScript.
33
44
Shows:
5+
56
- Multiple event types (input, click, change)
67
- Custom events for decoupled logic
78
- Working with form inputs
89
- Dynamic UI updates
910
"""
1011
from pyscript import when, Event
11-
from pyscript.web import page
12+
from pyscript.web import page, div
1213

1314

1415
# Custom event for when colour changes.
15-
colour_changed = Event()
16-
16+
_colour_has_changed = Event()
1717
# Colour history (limited to 10).
18-
history = []
18+
_HISTORY = []
1919

2020

2121
def rgb_to_hex(r, g, b):
2222
"""
23-
Convert RGB values to hex colour string.
23+
Convert RGB values to a hex colour string.
2424
"""
2525
return f"#{r:02X}{g:02X}{b:02X}"
2626

2727

2828
def hex_to_rgb(hex_colour):
2929
"""
30-
Convert hex colour string to RGB tuple.
30+
Convert a hex colour string to an RGB tuple.
3131
"""
3232
hex_colour = hex_colour.lstrip("#")
3333
return tuple(int(hex_colour[i:i+2], 16) for i in (0, 2, 4))
@@ -60,34 +60,28 @@ def update_controls(r, g, b):
6060
page["#red-slider"].value = r
6161
page["#green-slider"].value = g
6262
page["#blue-slider"].value = b
63-
6463
# Update number inputs.
6564
page["#red-value"].value = r
6665
page["#green-value"].value = g
6766
page["#blue-value"].value = b
68-
6967
# Update hex input.
7068
hex_colour = rgb_to_hex(r, g, b)
7169
page["#hex-input"].value = hex_colour
72-
7370
# Update display.
7471
update_display(hex_colour)
75-
7672
# Trigger custom event.
77-
colour_changed.trigger(hex_colour)
73+
_colour_has_changed.trigger(hex_colour)
7874

7975

8076
def add_to_history(hex_colour):
8177
"""
8278
Add colour to history, maintaining max of 10 items.
8379
"""
84-
if hex_colour in history:
80+
if hex_colour in _HISTORY:
8581
return
86-
87-
history.insert(0, hex_colour)
88-
if len(history) > 10:
89-
history.pop()
90-
82+
_HISTORY.insert(0, hex_colour)
83+
if len(_HISTORY) > 10:
84+
_HISTORY.pop()
9185
# Update history display.
9286
render_history()
9387

@@ -96,14 +90,11 @@ def render_history():
9690
"""
9791
Render colour history.
9892
"""
99-
from pyscript.web import div
100-
10193
container = page["#history-colours"]
10294
container.clear()
103-
104-
for colour in history:
95+
for colour in _HISTORY:
10596
colour_div = div(Class="history-colour", title=colour)
106-
colour_div.style.backgroundColor = colour
97+
colour_div.style["backgroundColor"] = colour
10798
colour_div.dataset.colour = colour
10899
container.append(colour_div)
109100

@@ -129,12 +120,10 @@ def handle_number_change(event):
129120
r = int(page["#red-value"].value)
130121
g = int(page["#green-value"].value)
131122
b = int(page["#blue-value"].value)
132-
133123
# Clamp values.
134124
r = max(0, min(255, r))
135125
g = max(0, min(255, g))
136126
b = max(0, min(255, b))
137-
138127
update_controls(r, g, b)
139128

140129

@@ -144,11 +133,9 @@ def handle_hex_change(event):
144133
Handle hex input changes.
145134
"""
146135
hex_colour = event.target.value.strip()
147-
148136
# Validate hex colour.
149137
if not hex_colour.startswith("#"):
150138
hex_colour = "#" + hex_colour
151-
152139
try:
153140
r, g, b = hex_to_rgb(hex_colour)
154141
update_controls(r, g, b)
@@ -177,7 +164,7 @@ def handle_history_click(event):
177164
update_controls(r, g, b)
178165

179166

180-
@when(colour_changed)
167+
@when(_colour_has_changed)
181168
def handle_colour_changed(hex_colour):
182169
"""
183170
Handle custom colour changed event.

docs/example-apps/display-demo/index.html

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
<meta charset="utf-8" />
55
<meta name="viewport" content="width=device-width,initial-scale=1" />
66
<title>Display Demo</title>
7-
<link rel="stylesheet" href="https://pyscript.net/releases/2025.11.2/core.css">
8-
<script type="module" src="https://pyscript.net/releases/2025.11.2/core.js"></script>
7+
<link rel="stylesheet"
8+
href="https://pyscript.net/releases/2025.11.2/core.css">
9+
<script type="module"
10+
src="https://pyscript.net/releases/2025.11.2/core.js"></script>
911
<style>
1012
body {
1113
font-family: system-ui, -apple-system, sans-serif;
@@ -42,6 +44,12 @@
4244
border-radius: 4px;
4345
border: 1px solid #dee2e6;
4446
min-height: 100px;
47+
overflow: hidden;
48+
}
49+
.output img {
50+
max-width: 100%;
51+
height: auto;
52+
display: block;
4553
}
4654
button {
4755
background: #3498db;
@@ -72,6 +80,23 @@
7280
opacity: 0.9;
7381
font-size: 0.9rem;
7482
}
83+
.loading {
84+
text-align: center;
85+
color: #666;
86+
}
87+
.spinner {
88+
border: 3px solid #f3f3f3;
89+
border-top: 3px solid #3498db;
90+
border-radius: 50%;
91+
width: 40px;
92+
height: 40px;
93+
animation: spin 1s linear infinite;
94+
margin: 1rem auto;
95+
}
96+
@keyframes spin {
97+
0% { transform: rotate(0deg); }
98+
100% { transform: rotate(360deg); }
99+
}
75100
</style>
76101
</head>
77102
<body>
@@ -80,7 +105,12 @@ <h1>Display Capabilities Demo</h1>
80105
<div class="grid">
81106
<div class="panel">
82107
<h2>Basic Types</h2>
83-
<div id="basic-output" class="output"></div>
108+
<div id="basic-output" class="output">
109+
<div class="loading">
110+
<div class="spinner"></div>
111+
<p>Loading PyScript...</p>
112+
</div>
113+
</div>
84114
<button id="btn-basic">Show Basic Types</button>
85115
</div>
86116

@@ -113,8 +143,25 @@ <h2>Incremental Updates</h2>
113143
<div id="incremental-output" class="output"></div>
114144
<button id="btn-incremental">Start Updates</button>
115145
</div>
146+
147+
<div class="panel">
148+
<h2>Pandas DataFrame</h2>
149+
<div id="dataframe-output" class="output"></div>
150+
<button id="btn-dataframe">Show DataFrame</button>
151+
</div>
152+
153+
<div class="panel">
154+
<h2>Matplotlib Plot</h2>
155+
<div id="plot-output" class="output"></div>
156+
<button id="btn-plot">Generate Plot</button>
157+
</div>
158+
159+
<div class="panel">
160+
<h2>Multiple Plots</h2>
161+
<div id="multiplot-output" class="output"></div>
162+
<button id="btn-multiplot">Show Subplots</button>
163+
</div>
116164
</div>
117-
118-
<script type="mpy" src="./main.py"></script>
165+
<script type="py" src="./main.py" config="./pyscript.json"></script>
119166
</body>
120167
</html>

0 commit comments

Comments
 (0)