mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-19 18:27:29 -05:00
Compare commits
481 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a3e2834b6 | ||
|
|
c0d45d368b | ||
|
|
f18ec3d20a | ||
|
|
b0377cc7ab | ||
|
|
96e671b55f | ||
|
|
40e99abbdf | ||
|
|
8b6b055681 | ||
|
|
8e5605fa42 | ||
|
|
06e1fdecc2 | ||
|
|
a82e8334d6 | ||
|
|
539bc2ae0e | ||
|
|
0711acd30e | ||
|
|
1476131ab4 | ||
|
|
89902a440c | ||
|
|
156c23d550 | ||
|
|
30396ba79a | ||
|
|
a4343c62ca | ||
|
|
4b89c84692 | ||
|
|
df68449b82 | ||
|
|
48e3383f66 | ||
|
|
e750fa7393 | ||
|
|
5a15199a3a | ||
|
|
1801472fc4 | ||
|
|
ab15ac37ff | ||
|
|
0955a6be49 | ||
|
|
d58237ea15 | ||
|
|
2d50ca86a6 | ||
|
|
f1a46be738 | ||
|
|
3e2a67d434 | ||
|
|
aef028be6e | ||
|
|
c8ec29a3d8 | ||
|
|
e81830a2ea | ||
|
|
54df7171a2 | ||
|
|
b31af823d1 | ||
|
|
72f266532b | ||
|
|
d9bf5cae12 | ||
|
|
cd95a42e5e | ||
|
|
e67eb06d8b | ||
|
|
28d37cdead | ||
|
|
13604e0a47 | ||
|
|
aeb6f1a755 | ||
|
|
92e6f711b7 | ||
|
|
a24113f42b | ||
|
|
7a6f8ab3ad | ||
|
|
6dd242f3ce | ||
|
|
88fa82c61a | ||
|
|
2299ba5f61 | ||
|
|
117df6ca38 | ||
|
|
4256a81653 | ||
|
|
d5b6935c0b | ||
|
|
b4503ef729 | ||
|
|
a00a6750b4 | ||
|
|
a08f891b20 | ||
|
|
bc1cac9c41 | ||
|
|
50f7ab0f34 | ||
|
|
fdc35ce3ed | ||
|
|
5c4e400d32 | ||
|
|
7a23e355b9 | ||
|
|
dffac642a1 | ||
|
|
97699eaded | ||
|
|
c6aaacdbf1 | ||
|
|
abfc68765f | ||
|
|
3ac2ac0982 | ||
|
|
b9a1227e47 | ||
|
|
801c63947a | ||
|
|
ffee4add4a | ||
|
|
f0be7ef418 | ||
|
|
e4eedd80bc | ||
|
|
c9e7fe16e4 | ||
|
|
5079dd19cb | ||
|
|
b4c686f411 | ||
|
|
287d0fa1af | ||
|
|
b78455c4c1 | ||
|
|
312b6b0706 | ||
|
|
924e530096 | ||
|
|
ef8918f3a7 | ||
|
|
91ae242e49 | ||
|
|
fd307e52ae | ||
|
|
a68967c773 | ||
|
|
52da45bb9c | ||
|
|
ad0dde3f17 | ||
|
|
8f3c36deea | ||
|
|
23e1ab81b3 | ||
|
|
77b40aa348 | ||
|
|
f6decfd93d | ||
|
|
e8d5138cfa | ||
|
|
a088fbd6fb | ||
|
|
19214901f9 | ||
|
|
c330a623b2 | ||
|
|
f77241e977 | ||
|
|
ed6de66c08 | ||
|
|
5191c45113 | ||
|
|
840bc803b7 | ||
|
|
00fdc73015 | ||
|
|
9660976d1d | ||
|
|
7f666dc6a0 | ||
|
|
e2a2292a6f | ||
|
|
4d89cbde01 | ||
|
|
d8e1cb8b0f | ||
|
|
3aef5a99dc | ||
|
|
7994207c78 | ||
|
|
f376097a15 | ||
|
|
2a2ff4066d | ||
|
|
32c3fb72cc | ||
|
|
e44e18114d | ||
|
|
7d2df4895e | ||
|
|
59db56feec | ||
|
|
fd60b4789a | ||
|
|
0696e4682d | ||
|
|
d56eeb59ed | ||
|
|
1d015c7534 | ||
|
|
264675d0c3 | ||
|
|
37d4cb7c48 | ||
|
|
cabb1c72b6 | ||
|
|
489a2bb20e | ||
|
|
d5f42e57ce | ||
|
|
94b0bf4131 | ||
|
|
12428c0617 | ||
|
|
ef44df5dda | ||
|
|
da3b43abdd | ||
|
|
4cc9647dc6 | ||
|
|
74cd7c840a | ||
|
|
0f2deeb71a | ||
|
|
93539c9b5a | ||
|
|
e48e6276e1 | ||
|
|
75a57a49f5 | ||
|
|
8a1db288fc | ||
|
|
84dcde188b | ||
|
|
27c91e9703 | ||
|
|
b5a0cd4057 | ||
|
|
77d8fe3562 | ||
|
|
a484aff457 | ||
|
|
c96f5912df | ||
|
|
8a01a56e51 | ||
|
|
2774e49ab9 | ||
|
|
26e7a54f1f | ||
|
|
f0e69cbc36 | ||
|
|
413428f535 | ||
|
|
0c54036466 | ||
|
|
2555833831 | ||
|
|
7e0aceced1 | ||
|
|
77234f6df3 | ||
|
|
45af96aad4 | ||
|
|
184d29055e | ||
|
|
9e73181816 | ||
|
|
0b0e03456c | ||
|
|
c6b5ce7f55 | ||
|
|
a14e701be4 | ||
|
|
7813c3f03f | ||
|
|
3a3cb7b11d | ||
|
|
d7b0731385 | ||
|
|
df8973736f | ||
|
|
9121071ba3 | ||
|
|
bf6470c046 | ||
|
|
3b7099cd3d | ||
|
|
f6dfc5361e | ||
|
|
0a7e1ce0d7 | ||
|
|
d6b1c393f6 | ||
|
|
bccd5e3750 | ||
|
|
6df5905b2b | ||
|
|
6284c02032 | ||
|
|
db27d52352 | ||
|
|
8ba28989fb | ||
|
|
da544929ac | ||
|
|
bb364b0524 | ||
|
|
818614b798 | ||
|
|
50b1a1d7c5 | ||
|
|
7d3b792a79 | ||
|
|
af72e232c3 | ||
|
|
0cdbfbeb30 | ||
|
|
339e40063a | ||
|
|
4467898473 | ||
|
|
17d16b987f | ||
|
|
8e86daac71 | ||
|
|
856720da49 | ||
|
|
8f2c150d1e | ||
|
|
7d8b4c980a | ||
|
|
932756c7a0 | ||
|
|
538aac9a28 | ||
|
|
856bf8f5fb | ||
|
|
e1758ae2e2 | ||
|
|
61b3154461 | ||
|
|
fb9b30d144 | ||
|
|
b0df96b13f | ||
|
|
a469062a32 | ||
|
|
89d5d5c7db | ||
|
|
b8c2d6b05d | ||
|
|
b247864414 | ||
|
|
d3bcd87cfa | ||
|
|
82e5b64bad | ||
|
|
73e0271c23 | ||
|
|
a2dabee0e9 | ||
|
|
6a27c6d9f2 | ||
|
|
213ced0c7f | ||
|
|
5086c23d47 | ||
|
|
ee345a5206 | ||
|
|
f74cddc3b1 | ||
|
|
5b986b8b26 | ||
|
|
14887b9814 | ||
|
|
ecc40315b3 | ||
|
|
e7aed7fcf0 | ||
|
|
cd1aa948f9 | ||
|
|
82613d016a | ||
|
|
3a66be585f | ||
|
|
0a4e36ae09 | ||
|
|
92643539cf | ||
|
|
a1281d1331 | ||
|
|
074ca0ef8f | ||
|
|
464a9633dc | ||
|
|
fc2d91c5bb | ||
|
|
d68169bffb | ||
|
|
7efdb04e1e | ||
|
|
0155e122fd | ||
|
|
eb03f16a77 | ||
|
|
5ac39641ab | ||
|
|
8d1e48e400 | ||
|
|
0021ccb49f | ||
|
|
8590c7e5b8 | ||
|
|
8c5475f78f | ||
|
|
dfa116eb70 | ||
|
|
3a9fd3c074 | ||
|
|
5a92ef3c11 | ||
|
|
d3902f5c93 | ||
|
|
c886f887ae | ||
|
|
fc5089ac59 | ||
|
|
e3602f464b | ||
|
|
f3db6a339c | ||
|
|
c05195c045 | ||
|
|
af981fc719 | ||
|
|
088a264910 | ||
|
|
d7e80ad51b | ||
|
|
b53ddd401f | ||
|
|
e9122bca9d | ||
|
|
b61e8435d1 | ||
|
|
146afb6532 | ||
|
|
854e9d1378 | ||
|
|
689878ce32 | ||
|
|
d7ab177cc5 | ||
|
|
f4c6093c47 | ||
|
|
9fedfe3699 | ||
|
|
26f07246e1 | ||
|
|
3ae4b3c4de | ||
|
|
c8f9f16791 | ||
|
|
88f0738500 | ||
|
|
03c79d5f2f | ||
|
|
e7c3b7bcfe | ||
|
|
c8becca044 | ||
|
|
543a27271f | ||
|
|
a62aba83a0 | ||
|
|
53c6cf5f45 | ||
|
|
89842e20da | ||
|
|
ef793aecf3 | ||
|
|
51d51409d3 | ||
|
|
371b5eac45 | ||
|
|
5319bd13d5 | ||
|
|
e10d055453 | ||
|
|
716254e655 | ||
|
|
4c00b1683f | ||
|
|
37c9db09c6 | ||
|
|
653e2c9be4 | ||
|
|
a2a9613da1 | ||
|
|
e8d92d0d34 | ||
|
|
755b98a8c0 | ||
|
|
13e9252260 | ||
|
|
6a9c27325a | ||
|
|
a1cb78eb85 | ||
|
|
716b57ebd3 | ||
|
|
8e231313b8 | ||
|
|
84e4e361c5 | ||
|
|
41a8d804e3 | ||
|
|
03e798a079 | ||
|
|
34a0205757 | ||
|
|
ba145f04ea | ||
|
|
22fd023635 | ||
|
|
08f34f748b | ||
|
|
7ffe6a598e | ||
|
|
71d24a445e | ||
|
|
6bcbbfb085 | ||
|
|
04fe1348d8 | ||
|
|
3033c779b0 | ||
|
|
4483f0db0f | ||
|
|
727267ae22 | ||
|
|
b5d15c2f7e | ||
|
|
589c614e57 | ||
|
|
4588e90226 | ||
|
|
8665a14dec | ||
|
|
43d598d951 | ||
|
|
68018cf078 | ||
|
|
ef4ab0d7a8 | ||
|
|
e66a2702df | ||
|
|
c57d4a7054 | ||
|
|
a36f08f0f1 | ||
|
|
760a8c75a5 | ||
|
|
740fd921e1 | ||
|
|
065c697070 | ||
|
|
e2c2459290 | ||
|
|
11c79a5344 | ||
|
|
429fe4c356 | ||
|
|
a18b4edfc0 | ||
|
|
b14a2bba5f | ||
|
|
1f825edc28 | ||
|
|
6ed834807a | ||
|
|
9a908e5fd0 | ||
|
|
4c30359b71 | ||
|
|
34dfe2d80b | ||
|
|
25bcff10b7 | ||
|
|
81268d0545 | ||
|
|
8f0a7706d7 | ||
|
|
46150f9b80 | ||
|
|
247745b7e7 | ||
|
|
94cc09b610 | ||
|
|
a210b2d5f5 | ||
|
|
12bf6db331 | ||
|
|
697ac9de9a | ||
|
|
4124bb5edc | ||
|
|
d55340a817 | ||
|
|
0de8cd9ab7 | ||
|
|
4e8281c749 | ||
|
|
357fbc644d | ||
|
|
7947a8a2dc | ||
|
|
35de3aa154 | ||
|
|
1ea687beb8 | ||
|
|
bb5c59307a | ||
|
|
5a3c414c8f | ||
|
|
cc4b460183 | ||
|
|
470c3489dd | ||
|
|
e1b4415193 | ||
|
|
77d98a565e | ||
|
|
412da2de08 | ||
|
|
dbdcd0b3d0 | ||
|
|
5c67384fbf | ||
|
|
35b0f9d377 | ||
|
|
95783bc284 | ||
|
|
4b840f7cbd | ||
|
|
f73d6cd9f2 | ||
|
|
15bb8f03ea | ||
|
|
059dbc88c9 | ||
|
|
c0f36aa047 | ||
|
|
d4120d2af3 | ||
|
|
dd1c008447 | ||
|
|
3721d2cd72 | ||
|
|
e0dda0e547 | ||
|
|
3c7568c72c | ||
|
|
6be1758548 | ||
|
|
25809660ef | ||
|
|
6b9eff45bb | ||
|
|
08e83feaf5 | ||
|
|
4f05b5afc6 | ||
|
|
9a5bf9918e | ||
|
|
1c7cf0ba7d | ||
|
|
ce2d1a4513 | ||
|
|
7d50d7eea0 | ||
|
|
e9411dc796 | ||
|
|
5cf2de16d1 | ||
|
|
e53bcf15a9 | ||
|
|
bec70b60b8 | ||
|
|
8b7fb89c68 | ||
|
|
b2bbdda73d | ||
|
|
ee2f46cfb9 | ||
|
|
4337e6833a | ||
|
|
a73c73b814 | ||
|
|
e8318a98f0 | ||
|
|
94f2ac6204 | ||
|
|
cc6cb4ded0 | ||
|
|
c61d4191c3 | ||
|
|
e284da7c09 | ||
|
|
9992096654 | ||
|
|
c696d92f40 | ||
|
|
af60299324 | ||
|
|
5aa9135a34 | ||
|
|
72e23ac86f | ||
|
|
33d49ad87d | ||
|
|
aa2335ca2e | ||
|
|
b31428006c | ||
|
|
dc1d583791 | ||
|
|
4299a74e40 | ||
|
|
3e408b7baa | ||
|
|
446c131ccb | ||
|
|
b062efcf17 | ||
|
|
30e31a86ef | ||
|
|
182272e8c7 | ||
|
|
06df21e8e3 | ||
|
|
cafebd68f2 | ||
|
|
061d4b3f72 | ||
|
|
6586e79d5e | ||
|
|
cda6c6bc7e | ||
|
|
a628026838 | ||
|
|
6700856b9f | ||
|
|
411aa0bbed | ||
|
|
0d79d31b96 | ||
|
|
cb05a9b067 | ||
|
|
536f359fb9 | ||
|
|
56e888ed33 | ||
|
|
687b93d148 | ||
|
|
0e1c396d7c | ||
|
|
7e24289703 | ||
|
|
0b23310a06 | ||
|
|
41ebaaf366 | ||
|
|
b79ceea7a8 | ||
|
|
b990bcb67a | ||
|
|
3f0f2d9910 | ||
|
|
4333f5f979 | ||
|
|
07e75293b8 | ||
|
|
a9ca7106cb | ||
|
|
da2728e6df | ||
|
|
adfa9a9b05 | ||
|
|
be9b9f66d3 | ||
|
|
9521bc7175 | ||
|
|
b445f8a834 | ||
|
|
3c3dffd5ed | ||
|
|
4c8443fd00 | ||
|
|
06a5a54103 | ||
|
|
0d3c3eef4e | ||
|
|
f0a6fb913f | ||
|
|
5f0c508fed | ||
|
|
16d9657982 | ||
|
|
40d098310e | ||
|
|
1345449d57 | ||
|
|
515858f313 | ||
|
|
2f452e9dc7 | ||
|
|
66119157a7 | ||
|
|
5b671dd1d0 | ||
|
|
1017362eec | ||
|
|
f67b8e0285 | ||
|
|
4c635fe84c | ||
|
|
68e463493e | ||
|
|
f1979d60b7 | ||
|
|
9150ebafec | ||
|
|
9543019336 | ||
|
|
1c53d91c6b | ||
|
|
4850f39b5a | ||
|
|
ab085c2d92 | ||
|
|
bf4d835948 | ||
|
|
214e39537b | ||
|
|
2d33afc195 | ||
|
|
87ea24ebd4 | ||
|
|
5380f8b9b3 | ||
|
|
00121ff8ba | ||
|
|
80e5d20e37 | ||
|
|
58f7c2137d | ||
|
|
f9194cc833 | ||
|
|
d9b8b48972 | ||
|
|
aa85f5f596 | ||
|
|
5341a0be4a | ||
|
|
0cfe20ca65 | ||
|
|
c352b502c4 | ||
|
|
58b4df6b3d | ||
|
|
29ba9436c8 | ||
|
|
2a044e88ad | ||
|
|
63092f9d72 | ||
|
|
0209324d57 | ||
|
|
1587273868 | ||
|
|
beb3aa1574 | ||
|
|
fe708c9fb4 | ||
|
|
e45d8bf973 | ||
|
|
b184c92f01 | ||
|
|
6c8afb05a7 | ||
|
|
d3dd4573cf | ||
|
|
d5cf68391a | ||
|
|
4e54e93450 | ||
|
|
e4f6387f18 | ||
|
|
54cb35b60a | ||
|
|
18ede2b729 | ||
|
|
f138b5a4f4 | ||
|
|
11a517bba4 | ||
|
|
66b57bf812 | ||
|
|
a9357bd97e | ||
|
|
d7c6d42c3d | ||
|
|
4dd1dc28b1 | ||
|
|
1e05ff7c95 | ||
|
|
e8e2e65584 | ||
|
|
3727e60152 | ||
|
|
0254012db6 | ||
|
|
8b97e4757f | ||
|
|
c70e121078 | ||
|
|
a4f97e6e46 | ||
|
|
800145a83c | ||
|
|
c75f885cb4 | ||
|
|
4011a51013 | ||
|
|
f4165dabcf | ||
|
|
de6c26eb05 |
12
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
12
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -2,7 +2,7 @@ name: Bug Report
|
||||
description: Create a report to help us improve
|
||||
labels: ["type: bug", "needs-triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for helping PyScript! 🐍
|
||||
@@ -14,7 +14,7 @@ body:
|
||||
There are also already a lot of open issues, so please take 2 minutes and search through existing ones to see if what you are experiencing already exists
|
||||
|
||||
Thanks for helping PyScript be amazing. We are nothing without people like you helping build a better community 💐!
|
||||
- type: checkboxes
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: Checklist
|
||||
@@ -26,7 +26,7 @@ body:
|
||||
required: true
|
||||
- label: I already searched in Google and didn't find any good information or help
|
||||
required: true
|
||||
- type: textarea
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
@@ -34,7 +34,7 @@ body:
|
||||
placeholder: Tell us what you see!
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
- type: dropdown
|
||||
id: browsers
|
||||
attributes:
|
||||
label: What browsers are you seeing the problem on? (if applicable)
|
||||
@@ -47,7 +47,7 @@ body:
|
||||
- Other
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
- type: textarea
|
||||
id: list
|
||||
attributes:
|
||||
label: Console info
|
||||
@@ -56,7 +56,7 @@ body:
|
||||
- Chrome , Firefox, and Edge: Right-click on the page and select *Inspect*. Alternatively you can press F12 on your keyboard.
|
||||
- Safari: Find instructions [here](https://support.apple.com/guide/safari/use-the-developer-tools-in-the-develop-menu-sfri20948/mac).
|
||||
render: shell
|
||||
- type: textarea
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional Context
|
||||
|
||||
7
.github/ISSUE_TEMPLATE/config.yml
vendored
7
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +1,8 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Question
|
||||
url: https://community.anaconda.cloud/c/tech-topics/pyscript
|
||||
- name: Feature Proposals
|
||||
url: https://github.com/pyscript/pyscript/discussions/new?category=proposals
|
||||
about: Create a feature request to make PyScript even better
|
||||
- name: Questions
|
||||
url: https://github.com/pyscript/pyscript/discussions/new?category=q-a
|
||||
about: For questions or discussions about pyscript
|
||||
|
||||
67
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
67
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
@@ -1,67 +0,0 @@
|
||||
name: Feature Request
|
||||
description: Create a feature request to make PyScript even better
|
||||
labels: ["type: enhancement", "needs-triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
### Thanks for helping PyScript! 🐍
|
||||
|
||||
Going through feature requests and issues takes up a lot of time, so please be so kind and take a few minutes to fill out all the areas to the best of your ability.
|
||||
|
||||
There will always be more great ideas than there is time to do them, and so we will need to selectively close issues that don't provide enough information, so everyone can focus our time on helping people like you who fill out the form completely. Thank you for your collaboration!
|
||||
|
||||
There are also already a lot of open requests, so please take 2 minutes and search through existing ones to see if your idea already exists. If you find something close, please upvote that request and comment.
|
||||
|
||||
Thanks for helping PyScript be amazing. We are nothing without people like you helping build a better community 💐!
|
||||
|
||||
### Lets make sure you are in the right place. If you have an idea/request for:
|
||||
|
||||
- #### A specific package/library (such as pandas or scikit learn):
|
||||
|
||||
Search for that respective library on github repo or website. You will have much more success there.
|
||||
|
||||
- #### A general Python question/feature request:
|
||||
|
||||
Try out a forum post [here](https://discuss.python.org/c/users/7)
|
||||
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: Checklist
|
||||
description: Please confirm and check all the following options
|
||||
options:
|
||||
- label: I added a descriptive title
|
||||
required: true
|
||||
- label: I searched for other feature requests and couldn't find a duplicate (including also the ``type-feature`` tag)
|
||||
required: true
|
||||
- label: I confirmed that it's not related to another project area (see the above section)
|
||||
required: true
|
||||
- type: textarea
|
||||
id: request-idea
|
||||
attributes:
|
||||
label: What is the idea?
|
||||
description: Describe what the feature is and the desired state
|
||||
placeholder: This feature would allow any user of PyScript to type in a simple command in the console and show all variables currently in use
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: why
|
||||
attributes:
|
||||
label: Why is this needed
|
||||
description: |
|
||||
Who would benefit from this and why would this add value to them? What problem does this solve?
|
||||
placeholder: This would benefit users who would like to see what is being used so they can learn and debug faster
|
||||
- type: textarea
|
||||
id: what
|
||||
attributes:
|
||||
label: What should happen?
|
||||
description: |
|
||||
What should be the user experience with the feature? Describe from a user perpective what they would do and see
|
||||
placeholder: A user would type in ``PyScript debug`` in the browser console and see a list of all variables created.
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: |
|
||||
Is there any other information that you think would be valuable for the team to know?
|
||||
37
.github/ISSUE_TEMPLATE/misc.yml
vendored
37
.github/ISSUE_TEMPLATE/misc.yml
vendored
@@ -1,37 +0,0 @@
|
||||
name: Miscellaneous
|
||||
description: For issues that don't belong in other categories
|
||||
labels: ["type: misc", "needs-triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for helping PyScript! 🐍
|
||||
|
||||
This issue is for things that doesn't make sense to put into the other issue categories and we don't want it to get lost.
|
||||
|
||||
Going through issues takes up a lot of time, so please be so kind and take a few minutes to fill out all the areas to the best of your ability.
|
||||
|
||||
There will always be more issues than there is time to do them, and so we will need to selectively close issues that don't provide enough information, so we can focus our time on helping people like you who fill out the issue form completely. Thank you for your collaboration!
|
||||
|
||||
There are also already a lot of open issues, so please take 2 minutes and search through existing ones to see if what you are experiencing already exists
|
||||
|
||||
Thanks for helping PyScript be amazing. We are nothing without people like you helping build a better community 💐!
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: Checklist
|
||||
description: Please confirm and check all the following options.
|
||||
options:
|
||||
- label: I added a descriptive title
|
||||
required: true
|
||||
- label: I searched for other issues and couldn't find a duplication
|
||||
required: true
|
||||
- label: I already searched in Google and didn't find any good information or help
|
||||
required: true
|
||||
- type: textarea
|
||||
id: what
|
||||
attributes:
|
||||
label: What is the issue/comment/problem?
|
||||
description: This is a miscellaneous issue so this could be just about anything. We simply ask that you provide as many details as you can to help spur discussion or the outcome you want.
|
||||
validations:
|
||||
required: true
|
||||
15
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
15
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
## Description
|
||||
|
||||
<!--Please describe the changes in your pull request in few words here. -->
|
||||
|
||||
## Changes
|
||||
|
||||
<!-- List the changes done to fix a bug or introduce a new feature.Please note both user-facing changes and changes to internal API's here -->
|
||||
|
||||
## Checklist
|
||||
|
||||
<!-- Note: Only user-facing changes require a changelog entry. Internal-only API changes do not require a changelog entry. Changes in documentation do not require a changelog entry. -->
|
||||
|
||||
- [ ] All tests pass locally
|
||||
- [ ] I have updated `CHANGELOG.md`
|
||||
- [ ] I have created documentation for this(if applicable)
|
||||
99
.github/workflows/build-unstable.yml
vendored
99
.github/workflows/build-unstable.yml
vendored
@@ -1,99 +0,0 @@
|
||||
name: '[CI] Build Unstable'
|
||||
|
||||
on:
|
||||
push: # Only run on merges into main that modify files under pyscriptjs/
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- pyscriptjs/**
|
||||
- .github/workflows/build-latest.yml # Test that workflow works when changed
|
||||
|
||||
pull_request: # Run on any PR that modifies files under pyscriptjs/
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- pyscriptjs/**
|
||||
- .github/workflows/build-unstable.yml # Test that workflow works when changed
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
BuildAndTest:
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: pyscriptjs
|
||||
env:
|
||||
MINICONDA_PYTHON_VERSION: py38
|
||||
MINICONDA_VERSION: 4.11.0
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.x
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
cache-name: cache-node-modules
|
||||
with:
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: setup Miniconda
|
||||
uses: conda-incubator/setup-miniconda@v2
|
||||
|
||||
- name: Setup Environment
|
||||
run: make setup
|
||||
|
||||
- name: Build
|
||||
run: make build
|
||||
|
||||
- name: TypeScript Tests
|
||||
run: make test-ts
|
||||
|
||||
- name: Python Tests
|
||||
run: make test-py
|
||||
|
||||
- name: Integration Tests
|
||||
run: make test-integration
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: pyscript
|
||||
path: |
|
||||
pyscriptjs/build/
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
Deploy:
|
||||
runs-on: ubuntu-latest
|
||||
needs: BuildAndTest
|
||||
if: github.ref == 'refs/heads/main' # Only deploy on merge into main
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: pyscript
|
||||
path: ./build/
|
||||
|
||||
# Deploy to S3
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||
with:
|
||||
aws-region: ${{ secrets.AWS_REGION }}
|
||||
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||
|
||||
- name: Sync to S3
|
||||
run: aws s3 sync --quiet ./build/ s3://pyscript.net/unstable/
|
||||
18
.github/workflows/dashboard.yaml
vendored
18
.github/workflows/dashboard.yaml
vendored
@@ -1,18 +0,0 @@
|
||||
name: Push issue to Github Project dashboard
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
|
||||
jobs:
|
||||
add_to_project:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/add-to-project@v0.0.3
|
||||
with:
|
||||
project-url: https://github.com/orgs/pyscript/projects/4/
|
||||
github-token: ${{ secrets.PROJECT_TOKEN }}
|
||||
60
.github/workflows/docs-latest.yml
vendored
60
.github/workflows/docs-latest.yml
vendored
@@ -1,60 +0,0 @@
|
||||
name: '[Docs] Build Latest'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- docs/**
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
env:
|
||||
SPHINX_HTML_BASE_URL: https://docs.pyscript.net/
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
|
||||
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
|
||||
|
||||
- name: Setup
|
||||
uses: conda-incubator/setup-miniconda@v2
|
||||
with:
|
||||
auto-update-conda: true
|
||||
activate-environment: docs
|
||||
environment-file: docs/environment.yml
|
||||
python-version: '3.9'
|
||||
|
||||
- name: Build
|
||||
shell: bash -l {0}
|
||||
run: |
|
||||
cd docs/
|
||||
make html
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: pyscript-docs-latest
|
||||
path: docs/_build/html/
|
||||
|
||||
# Deploy to S3
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||
with:
|
||||
aws-region: ${{ secrets.AWS_REGION }}
|
||||
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||
|
||||
- name: Copy redirect file
|
||||
run: aws s3 cp --quiet ./docs/_build/html/_static/redirect.html s3://docs.pyscript.net/index.html
|
||||
|
||||
# - name: Delete latest directory
|
||||
# run: aws s3 rm --recursive s3://docs.pyscript.net/latest/
|
||||
|
||||
- name: Sync to S3
|
||||
run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/latest/
|
||||
57
.github/workflows/docs-release.yml
vendored
57
.github/workflows/docs-release.yml
vendored
@@ -1,57 +0,0 @@
|
||||
name: '[Docs] Build Release'
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
env:
|
||||
SPHINX_HTML_BASE_URL: https://docs.pyscript.net/
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
|
||||
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
|
||||
|
||||
- name: Setup
|
||||
uses: conda-incubator/setup-miniconda@v2
|
||||
with:
|
||||
auto-update-conda: true
|
||||
activate-environment: docs
|
||||
environment-file: docs/environment.yml
|
||||
python-version: '3.9'
|
||||
|
||||
- name: Build
|
||||
shell: bash -l {0}
|
||||
run: |
|
||||
cd docs/
|
||||
make html
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: pyscript-docs-${{ github.ref_name }}
|
||||
path: docs/_build/html/
|
||||
|
||||
# Deploy to S3
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||
with:
|
||||
aws-region: ${{ secrets.AWS_REGION }}
|
||||
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||
|
||||
- name: Copy redirect file
|
||||
run: aws s3 cp --quiet ./docs/_build/html/_static/redirect.html s3://docs.pyscript.net/index.html
|
||||
|
||||
# - name: Delete release directory
|
||||
# run: aws s3 rm --recursive s3://docs.pyscript.net/${{ github.ref_name }}/
|
||||
|
||||
- name: Sync to S3
|
||||
run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/${{ github.ref_name }}/
|
||||
77
.github/workflows/docs-review.yml
vendored
77
.github/workflows/docs-review.yml
vendored
@@ -1,77 +0,0 @@
|
||||
name: '[Docs] Build Review'
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- docs/**
|
||||
|
||||
concurrency:
|
||||
# Concurrency group that uses the workflow name and PR number if available
|
||||
# or commit SHA as a fallback. If a new build is triggered under that
|
||||
# concurrency group while a previous build is running it will be canceled.
|
||||
# Repeated pushes to a PR will cancel all previous builds, while multiple
|
||||
# merges to main will not cancel.
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: github.repository_owner == 'pyscript'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
env:
|
||||
SPHINX_HTML_BASE_URL: https://docs.pyscript.net/
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
|
||||
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
|
||||
|
||||
- name: Setup
|
||||
uses: conda-incubator/setup-miniconda@v2
|
||||
with:
|
||||
auto-update-conda: true
|
||||
activate-environment: docs
|
||||
environment-file: docs/environment.yml
|
||||
python-version: '3.9'
|
||||
|
||||
- name: Build
|
||||
shell: bash -l {0}
|
||||
run: |
|
||||
cd docs/
|
||||
make html
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: pyscript-docs-review-${{ github.event.number }}
|
||||
path: docs/_build/html/
|
||||
|
||||
# Deploy to S3
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||
with:
|
||||
aws-region: ${{ secrets.AWS_REGION }}
|
||||
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||
|
||||
- name: Copy redirect file
|
||||
run: aws s3 cp --quiet ./docs/_build/html/_static/redirect.html s3://docs.pyscript.net/index.html
|
||||
|
||||
# - name: Delete review directory
|
||||
# run: aws s3 rm --recursive s3://docs.pyscript.net/review/${{ github.event.number }}/
|
||||
|
||||
- name: Sync to S3
|
||||
run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/review/${{ github.event.number }}/
|
||||
|
||||
- name: Adding step summary
|
||||
run: |
|
||||
echo "### Review documentation" >> $GITHUB_STEP_SUMMARY
|
||||
echo "As with any pull request, you can find the rendered documentation version for pull request ${{ github.event.number }} here:"
|
||||
echo "" >> $GITHUB_STEP_SUMMARY # this is a blank line
|
||||
echo "https://docs.pyscript.net/review/${{ github.event.number }}/" >> $GITHUB_STEP_SUMMARY
|
||||
32
.github/workflows/prepare-release.yml
vendored
32
.github/workflows/prepare-release.yml
vendored
@@ -1,25 +1,20 @@
|
||||
name: '[CI] Prepare Release'
|
||||
name: "Prepare Release"
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '[0-9][0-9][0-9][0-9].[0-9][0-9].[0-9]+' # YYYY.MM.MICRO
|
||||
|
||||
env:
|
||||
MINICONDA_PYTHON_VERSION: py38
|
||||
MINICONDA_VERSION: 4.11.0
|
||||
- "[0-9][0-9][0-9][0-9].[0-9][0-9].[0-9]+" # YYYY.MM.MICRO
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: pyscriptjs
|
||||
working-directory: ./pyscript.core
|
||||
|
||||
jobs:
|
||||
build:
|
||||
prepare-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v3
|
||||
@@ -39,14 +34,18 @@ jobs:
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: setup Miniconda
|
||||
uses: conda-incubator/setup-miniconda@v2
|
||||
- name: NPM Install
|
||||
run: npm install && npx playwright install
|
||||
|
||||
- name: Setup Environment
|
||||
run: make setup
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
- name: Build and Test
|
||||
run: make test
|
||||
- name: Generate index.html
|
||||
working-directory: .
|
||||
run: sed 's#_PATH_#./#' ./public/index.html > ./pyscript.core/dist/index.html
|
||||
|
||||
- name: Zip dist folder
|
||||
run: zip -r -q ./build.zip ./dist
|
||||
|
||||
- name: Prepare Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
@@ -54,3 +53,4 @@ jobs:
|
||||
draft: true
|
||||
prerelease: true
|
||||
generate_release_notes: true
|
||||
files: ./build.zip
|
||||
|
||||
37
.github/workflows/publish-release.yml
vendored
37
.github/workflows/publish-release.yml
vendored
@@ -1,26 +1,22 @@
|
||||
name: '[CI] Publish Release'
|
||||
name: "Publish Release"
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
env:
|
||||
MINICONDA_PYTHON_VERSION: py38
|
||||
MINICONDA_VERSION: 4.11.0
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: pyscriptjs
|
||||
working-directory: ./pyscript.core
|
||||
|
||||
jobs:
|
||||
build:
|
||||
publish-release:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v3
|
||||
@@ -40,23 +36,24 @@ jobs:
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: setup Miniconda
|
||||
uses: conda-incubator/setup-miniconda@v2
|
||||
- name: npm install
|
||||
run: npm install && npx playwright install
|
||||
|
||||
- name: Setup Environment
|
||||
run: make setup
|
||||
- name: build
|
||||
run: npm run build
|
||||
|
||||
- name: Build and Test
|
||||
run: make test
|
||||
- name: Generate index.html in snapshot
|
||||
working-directory: .
|
||||
run: sed 's#_PATH_#https://pyscript.net/releases/${{ github.ref_name }}/#' ./public/index.html > ./pyscript.core/dist/index.html
|
||||
|
||||
# Upload to S3
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: ${{ secrets.AWS_REGION }}
|
||||
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||
|
||||
- name: Sync to S3
|
||||
run: | # Update /latest and create an explicitly versioned directory under releases/YYYY.MM.MICRO/
|
||||
aws s3 sync --quiet ./build/ s3://pyscript.net/latest/
|
||||
aws s3 sync --quiet ./build/ s3://pyscript.net/releases/${{ github.ref_name }}/
|
||||
run:
|
||||
| # Update /latest and create an explicitly versioned directory under releases/YYYY.MM.MICRO/
|
||||
aws s3 sync --quiet ./dist/ s3://pyscript.net/latest/
|
||||
aws s3 sync --quiet ./dist/ s3://pyscript.net/releases/${{ github.ref_name }}/
|
||||
|
||||
49
.github/workflows/publish-snapshot.yml
vendored
49
.github/workflows/publish-snapshot.yml
vendored
@@ -1,26 +1,61 @@
|
||||
name: '[CI] Publish Snapshot'
|
||||
# Copy /unstable/ to /snapshots/2022.09.1.RC1/
|
||||
name: "Publish Snapshot"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
snapshot_version:
|
||||
description: 'The calver version of this snapshot: 2022.09.1 or 2022.09.1.RC1'
|
||||
description: "The calver version of this snapshot: 2022.09.1 or 2022.09.1.RC1"
|
||||
type: string
|
||||
required: true
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./pyscript.core
|
||||
|
||||
jobs:
|
||||
snapshot:
|
||||
publish-snapshot:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.x
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
cache-name: cache-node-modules
|
||||
with:
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm install && npx playwright install
|
||||
|
||||
- name: Build Pyscript.core
|
||||
run: npm run build
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: ${{ secrets.AWS_REGION }}
|
||||
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||
- name: Sync to S3
|
||||
|
||||
- name: Generate index.html in snapshot
|
||||
working-directory: .
|
||||
run: sed 's#_PATH_#https://pyscript.net/snapshots/${{ inputs.snapshot_version }}/#' ./public/index.html > ./pyscript.core/dist/index.html
|
||||
|
||||
- name: Copy to Snapshot
|
||||
run: >
|
||||
aws s3 sync s3://pyscript.net/unstable/ s3://pyscript.net/snapshots/${{ inputs.snapshot_version }}/
|
||||
aws s3 sync ./dist/ s3://pyscript.net/snapshots/${{ inputs.snapshot_version }}/
|
||||
|
||||
61
.github/workflows/publish-unstable.yml
vendored
Normal file
61
.github/workflows/publish-unstable.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
name: "Publish Unstable"
|
||||
|
||||
on:
|
||||
push: # Only run on merges into main that modify files under pyscript.core/ and examples/
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- pyscript.core/**
|
||||
- examples/**
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
publish-unstable:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./pyscript.core
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.x
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
cache-name: cache-node-modules
|
||||
with:
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: NPM Install
|
||||
run: npm install && npx playwright install
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
- name: Generate index.html in snapshot
|
||||
working-directory: .
|
||||
run: sed 's#_PATH_#https://pyscript.net/unstable/#' ./public/index.html > ./pyscript.core/dist/index.html
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: ${{ secrets.AWS_REGION }}
|
||||
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||
|
||||
- name: Sync to S3
|
||||
run: aws s3 sync --quiet ./dist/ s3://pyscript.net/unstable/
|
||||
29
.github/workflows/sync-examples.yml
vendored
29
.github/workflows/sync-examples.yml
vendored
@@ -1,29 +0,0 @@
|
||||
name: '[CI] Sync Examples'
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
defaults:
|
||||
run:
|
||||
working-directory: examples
|
||||
|
||||
steps:
|
||||
|
||||
# Deploy to S3
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||
with:
|
||||
aws-region: ${{ secrets.AWS_REGION }}
|
||||
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||
- name: Sync to S3
|
||||
# Sync outdated or new files, delete ones no longer in source
|
||||
run: aws s3 sync --quiet --delete . s3://pyscript.net/examples/ # Sync directory, delete what is not in source
|
||||
92
.github/workflows/test.yml
vendored
Normal file
92
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
name: "[CI] Test"
|
||||
|
||||
on:
|
||||
push: # Only run on merges into main that modify certain files
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- pyscript.core/**
|
||||
- .github/workflows/test.yml
|
||||
|
||||
pull_request: # Only run on merges into main that modify certain files
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- pyscript.core/**
|
||||
- .github/workflows/test.yml
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
BuildAndTest:
|
||||
runs-on: ubuntu-latest-8core
|
||||
env:
|
||||
MINICONDA_PYTHON_VERSION: py38
|
||||
MINICONDA_VERSION: 4.11.0
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 3
|
||||
|
||||
# display a git log: when you run CI on PRs, github automatically
|
||||
# merges the PR into main and run the CI on that commit. The idea
|
||||
# here is to show enough of git log to understand what is the
|
||||
# actual commit (in the PR) that we are using. See also
|
||||
# 'fetch-depth: 3' above.
|
||||
- name: git log
|
||||
run: git log --graph -3
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20.x
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
cache-name: cache-node-modules
|
||||
with:
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: setup Miniconda
|
||||
uses: conda-incubator/setup-miniconda@v2
|
||||
|
||||
- name: Create and activate virtual environment
|
||||
run: |
|
||||
python3 -m venv test_venv
|
||||
source test_venv/bin/activate
|
||||
echo PATH=$PATH >> $GITHUB_ENV
|
||||
echo VIRTUAL_ENV=$VIRTUAL_ENV >> $GITHUB_ENV
|
||||
|
||||
- name: Setup dependencies in virtual environment
|
||||
run: |
|
||||
make setup
|
||||
|
||||
- name: Build
|
||||
run: make build
|
||||
|
||||
- name: Integration Tests
|
||||
#run: make test-integration-parallel
|
||||
run: |
|
||||
make test-integration
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: pyscript
|
||||
path: |
|
||||
pyscript.core/dist/
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: success() || failure()
|
||||
with:
|
||||
name: test_results
|
||||
path: test_results/
|
||||
if-no-files-found: error
|
||||
16
.github/workflows/test_report.yml
vendored
Normal file
16
.github/workflows/test_report.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
name: Test Report
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ['\[CI\] Test']
|
||||
types:
|
||||
- completed
|
||||
jobs:
|
||||
report:
|
||||
runs-on: ubuntu-latest-8core
|
||||
steps:
|
||||
- uses: dorny/test-reporter@v1.6.0
|
||||
with:
|
||||
artifact: test_results
|
||||
name: Test reports
|
||||
path: "*.xml"
|
||||
reporter: java-junit
|
||||
13
.gitignore
vendored
13
.gitignore
vendored
@@ -51,7 +51,6 @@ coverage.xml
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
pyscriptjs/examples
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
@@ -138,3 +137,15 @@ dmypy.json
|
||||
node_modules/
|
||||
|
||||
coverage/
|
||||
|
||||
# junit xml for test results
|
||||
test_results
|
||||
|
||||
# @pyscript/core npm artifacts
|
||||
pyscript.core/core.*
|
||||
pyscript.core/dist
|
||||
pyscript.core/dist.zip
|
||||
pyscript.core/src/plugins.js
|
||||
pyscript.core/src/stdlib/pyscript.js
|
||||
pyscript.core/src/3rd-party/*
|
||||
!pyscript.core/src/3rd-party/READMEmd
|
||||
|
||||
@@ -1,90 +1,53 @@
|
||||
# This is the configuration for pre-commit, a local framework for managing pre-commit hooks
|
||||
# Check out the docs at: https://pre-commit.com/
|
||||
ci:
|
||||
#skip: [eslint]
|
||||
autoupdate_schedule: monthly
|
||||
|
||||
default_stages: [commit]
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.3.0
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.0
|
||||
hooks:
|
||||
- id: check-builtin-literals
|
||||
- id: check-case-conflict
|
||||
- id: check-docstring-first
|
||||
- id: check-executables-have-shebangs
|
||||
- id: check-json
|
||||
exclude: tsconfig.json
|
||||
exclude: tsconfig\.json
|
||||
- id: check-toml
|
||||
exclude: bad\.toml
|
||||
- id: check-xml
|
||||
- id: check-yaml
|
||||
- id: detect-private-key
|
||||
- id: end-of-file-fixer
|
||||
exclude: \.min\.js$
|
||||
exclude: pyscript\.core/dist|\.min\.js$
|
||||
- id: trailing-whitespace
|
||||
|
||||
- repo: https://github.com/PyCQA/bandit
|
||||
rev: 1.7.4
|
||||
hooks:
|
||||
- id: bandit
|
||||
args:
|
||||
- --skip=B101,B201
|
||||
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 22.8.0
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 23.1.0
|
||||
hooks:
|
||||
- id: black
|
||||
exclude: pyscript\.core/src/stdlib/pyscript/__init__\.py
|
||||
|
||||
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.2.1
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.2.4
|
||||
hooks:
|
||||
- id: codespell # See 'setup.cfg' for args
|
||||
- id: codespell # See 'pyproject.toml' for args
|
||||
exclude: \.js\.map$
|
||||
additional_dependencies:
|
||||
- tomli
|
||||
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 5.0.4
|
||||
- repo: https://github.com/hoodmane/pyscript-prettier-precommit
|
||||
rev: "v3.0.0-alpha.6"
|
||||
hooks:
|
||||
- id: flake8 # See 'setup.cfg' for args
|
||||
additional_dependencies: [flake8-bugbear, flake8-comprehensions]
|
||||
- id: prettier
|
||||
exclude: pyscript\.core/test|pyscript\.core/dist|pyscript\.core/types|pyscript.core/src/stdlib/pyscript.js|pyscript\.sw/|pyscript.core/src/3rd-party
|
||||
args: [--tab-width, "4"]
|
||||
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.10.1
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.12.0
|
||||
hooks:
|
||||
- id: isort
|
||||
name: isort (python)
|
||||
args: [--profile, black]
|
||||
|
||||
- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
|
||||
rev: v2.4.0
|
||||
hooks:
|
||||
- id: pretty-format-yaml
|
||||
args: [--autofix, --indent, '4']
|
||||
exclude: .github/ISSUE_TEMPLATE/.*\.yml$
|
||||
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.38.2
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args:
|
||||
- --py310-plus
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-eslint
|
||||
rev: v8.24.0
|
||||
hooks:
|
||||
- id: eslint
|
||||
files: pyscriptjs/src/.*\.[jt]sx?$ # *.js, *.jsx, *.ts and *.tsx
|
||||
types: [file]
|
||||
additional_dependencies:
|
||||
- eslint
|
||||
- eslint-plugin-svelte3
|
||||
- typescript
|
||||
- '@typescript-eslint/eslint-plugin'
|
||||
- '@typescript-eslint/parser'
|
||||
|
||||
# Commented out until mdformat-myst supports custom extensions
|
||||
# See https://github.com/executablebooks/mdformat-myst/pull/9
|
||||
# - repo: https://github.com/executablebooks/mdformat
|
||||
# rev: 0.7.14 # Use the ref you want to point at
|
||||
# hooks:
|
||||
# - id: mdformat
|
||||
# additional_dependencies:
|
||||
# - mdformat-gfm
|
||||
# - mdformat-myst
|
||||
# - mdformat-black
|
||||
|
||||
5
.prettierignore
Normal file
5
.prettierignore
Normal file
@@ -0,0 +1,5 @@
|
||||
ISSUE_TEMPLATE
|
||||
*.min.*
|
||||
package-lock.json
|
||||
docs
|
||||
examples/panel.html
|
||||
87
CHANGELOG.md
Normal file
87
CHANGELOG.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# Release Notes
|
||||
|
||||
## 2023.05.01
|
||||
|
||||
### Features
|
||||
|
||||
- Added the `xterm` attribute to `py-config`. When set to `True` or `xterm`, an (output-only) [xterm.js](http://xtermjs.org/) terminal will be used in place of the default py-terminal.
|
||||
- The default version of Pyodide is now `0.23.2`. See the [Pyodide Changelog](https://pyodide.org/en/stable/project/changelog.html#version-0-23-2) for a detailed list of changes.
|
||||
- Added the `@when` decorator for attaching Python functions as event handlers
|
||||
- The `py-mount` attribute on HTML elements has been deprecated, and will be removed in a future release.
|
||||
|
||||
#### Runtime py- attributes
|
||||
|
||||
- Added logic to react to `py-*` attributes changes, removal, `py-*` attributes added to already live nodes but also `py-*` attributes added or defined via injected nodes (either appended or via `innerHTML` operations). ([#1435](https://github.com/pyscript/pyscript/pull/1435))
|
||||
|
||||
#### <script type="py">
|
||||
|
||||
- Added the ability to optionally use `<script type="py">`, `<script type="pyscript">` or `<script type="py-script">` instead of a `<py-script>` custom element, in order to tackle cases where the content of the `<py-script>` tag, inevitably parsed by browsers, could accidentally contain _HTML_ able to break the surrounding page layout. ([#1396](https://github.com/pyscript/pyscript/pull/1396))
|
||||
|
||||
#### <py-terminal>
|
||||
|
||||
- Added a `docked` field and attribute for the `<py-terminal>` custom element, enabled by default when the terminal is in `auto` mode, and able to dock the terminal at the bottom of the page with auto scroll on new code execution.
|
||||
|
||||
#### <py-script>
|
||||
|
||||
- Restored the `output` attribute of `py-script` tags to route `sys.stdout` to a DOM element with the given ID. ([#1063](https://github.com/pyscript/pyscript/pull/1063))
|
||||
- Added a `stderr` attribute of `py-script` tags to route `sys.stderr` to a DOM element with the given ID. ([#1063](https://github.com/pyscript/pyscript/pull/1063))
|
||||
|
||||
#### <py-repl>
|
||||
|
||||
- The `output` attribute of `py-repl` tags now specifies the id of the DOM element that `sys.stdout`, `sys.stderr`, and the results of a REPL execution are written to. It no longer affects the location of calls to `display()`
|
||||
- Added a `stderr` attribute of `py-repl` tags to route `sys.stderr` to a DOM element with the given ID. ([#1106](https://github.com/pyscript/pyscript/pull/1106))
|
||||
- Resored the `output-mode` attribute of `py-repl` tags. If `output-mode` == 'append', the DOM element where output is printed is _not_ cleared before writing new results.
|
||||
- Load code from the attribute src of py-repl and preload it into the corresponding py-repl tag by use the attribute `str` in your `py-repl` tag([#1292](https://github.com/pyscript/pyscript/pull/1292))
|
||||
- <py-repl> elements now have a `getPySrc()` method, which returns the code inside the REPL as a string.([#1516](https://github.com/pyscript/pyscript/pull/1292))
|
||||
|
||||
#### Plugins
|
||||
|
||||
- Plugins may now implement the `beforePyReplExec()` and `afterPyReplExec()` hooks, which are called immediately before and after code in a `py-repl` tag is executed. ([#1106](https://github.com/pyscript/pyscript/pull/1106))
|
||||
|
||||
#### Web worker support
|
||||
|
||||
- introduced the new experimental `execution_thread` config option: if you set `execution_thread = "worker"`, the python interpreter runs inside a web worker
|
||||
- worker support is still **very** experimental: not everything works, use it at your own risk
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Fixes [#1280](https://github.com/pyscript/pyscript/issues/1280), which describes the errors on the PyRepl tests related to having auto-gen tags that shouldn't be there.
|
||||
|
||||
### Enhancements
|
||||
|
||||
- Py-REPL tests now run on both osx and non osx OSs
|
||||
- migrated from _rollup_ to _esbuild_ to create artifacts
|
||||
- updated `@codemirror` dependency to its latest
|
||||
|
||||
### Docs
|
||||
|
||||
- Add docs for event handlers
|
||||
|
||||
## 2023.03.1
|
||||
|
||||
### Features
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Fixed an issue where `pyscript` would not be available when using the minified version of PyScript. ([#1054](https://github.com/pyscript/pyscript/pull/1054))
|
||||
- Fixed missing closing tag when rendering an image with `display`. ([#1058](https://github.com/pyscript/pyscript/pull/1058))
|
||||
- Fixed a bug where Python plugins methods were being executed twice. ([#1064](https://github.com/pyscript/pyscript/pull/1064))
|
||||
|
||||
### Enhancements
|
||||
|
||||
- When adding a `py-` attribute to an element but didn't added an `id` attribute, PyScript will now generate a random ID for the element instead of throwing an error which caused the splash screen to not shutdown. ([#1122](https://github.com/pyscript/pyscript/pull/1122))
|
||||
- You can now disable the splashscreen by setting `enabled = false` in your `py-config` under the `[splashscreen]` configuration section. ([#1138](https://github.com/pyscript/pyscript/pull/1138))
|
||||
|
||||
### Documentation
|
||||
|
||||
- Fixed 'Direct usage of document is deprecated' warning in the getting started guide. ([#1052](https://github.com/pyscript/pyscript/pull/1052))
|
||||
- Added reference documentation for the `py-splashscreen` plugin ([#1138](https://github.com/pyscript/pyscript/pull/1138))
|
||||
- Adds doc for installing tests ([#1156](https://github.com/pyscript/pyscript/pull/1156))
|
||||
- Adds docs for custom Pyscript attributes (`py-*`) that allow you to add event listeners to an element ([#1125](https://github.com/pyscript/pyscript/pull/1125))
|
||||
|
||||
### Deprecations and Removals
|
||||
|
||||
- The py-config `runtimes` to specify an interpreter has been deprecated. The `interpreters` config should be used instead. ([#1082](https://github.com/pyscript/pyscript/pull/1082))
|
||||
- The attributes `pys-onClick` and `pys-onKeyDown` have been deprecated, but the warning was only shown in the console. An alert banner will now be shown on the page if the attributes are used. They will be removed in the next release. ([#1084](https://github.com/pyscript/pyscript/pull/1084))
|
||||
- The pyscript elements `py-button`, `py-inputbox`, `py-box` and `py-title` have now completed their deprecation cycle and have been removed. ([#1084](https://github.com/pyscript/pyscript/pull/1084))
|
||||
- The attributes `pys-onClick` and `pys-onKeyDown` have been removed. Use `py-click` and `py-keydown` instead ([#1361](https://github.com/pyscript/pyscript/pull/1361))
|
||||
202
CONTRIBUTING.md
202
CONTRIBUTING.md
@@ -4,17 +4,24 @@ Thank you for wanting to contribute to the PyScript project!
|
||||
|
||||
## Table of contents
|
||||
|
||||
* [Code of Conduct](#code-of-conduct)
|
||||
* [Contributing](#contributing)
|
||||
* [Reporting bugs](#reporting-bugs)
|
||||
* [Reporting security issues](#reporting-security-issues)
|
||||
* [Asking questions](#asking-questions)
|
||||
* [Setting up your local environment](#setting-up-your-local-environment)
|
||||
* [Places to start](#places-to-start)
|
||||
* [Submitting a change](#submitting-a-change)
|
||||
* [License terms for contributions](#license-terms-for-contributions)
|
||||
* [Becoming a maintainer](#becoming-a-maintainer)
|
||||
* [Trademarks](#trademarks)
|
||||
- [Contributing to PyScript](#contributing-to-pyscript)
|
||||
- [Table of contents](#table-of-contents)
|
||||
- [Code of Conduct](#code-of-conduct)
|
||||
- [Contributing](#contributing)
|
||||
- [Reporting bugs](#reporting-bugs)
|
||||
- [Creating useful issues](#creating-useful-issues)
|
||||
- [Reporting security issues](#reporting-security-issues)
|
||||
- [Asking questions](#asking-questions)
|
||||
- [Setting up your local environment and developing](#setting-up-your-local-environment-and-developing)
|
||||
- [Developing](#developing)
|
||||
- [Rebasing changes](#rebasing-changes)
|
||||
- [Building the docs](#building-the-docs)
|
||||
- [Places to start](#places-to-start)
|
||||
- [Setting up your local environment and developing](#setting-up-your-local-environment-and-developing)
|
||||
- [Submitting a change](#submitting-a-change)
|
||||
- [License terms for contributions](#license-terms-for-contributions)
|
||||
- [Becoming a maintainer](#becoming-a-maintainer)
|
||||
- [Trademarks](#trademarks)
|
||||
|
||||
# Code of Conduct
|
||||
|
||||
@@ -28,10 +35,10 @@ Bugs are tracked on the [project issues page](https://github.com/pyscript/pyscri
|
||||
|
||||
## Creating useful issues
|
||||
|
||||
* Use a clear and descriptive title.
|
||||
* Describe the specific steps that reproduce the problem with as many details as possible so that someone can verify the issue.
|
||||
* Describe the behavior you observed, and the behavior you had expected.
|
||||
* Include screenshots if they help make the issue clear.
|
||||
- Use a clear and descriptive title.
|
||||
- Describe the specific steps that reproduce the problem with as many details as possible so that someone can verify the issue.
|
||||
- Describe the behavior you observed, and the behavior you had expected.
|
||||
- Include screenshots if they help make the issue clear.
|
||||
|
||||
## Reporting security issues
|
||||
|
||||
@@ -41,173 +48,25 @@ If you aren't confident that it is appropriate to submit a security issue using
|
||||
|
||||
If you have questions about the project, using PyScript, or anything else, please ask in the [PyScript forum](https://community.anaconda.cloud/c/tech-topics/pyscript).
|
||||
|
||||
## Setting up your local environment
|
||||
|
||||
* Fork the repository - [quicklink](https://github.com/pyscript/pyscript/fork)
|
||||
|
||||
* Clone your fork of the project
|
||||
|
||||
```
|
||||
git clone https://github.com/<your username>/pyscript
|
||||
```
|
||||
|
||||
* Add the original project as your upstream (this will allow you to pull the latest changes)
|
||||
|
||||
```
|
||||
git remote add upstream git@github.com:pyscript/pyscript.git
|
||||
```
|
||||
|
||||
* cd into the `pyscriptjs` folder using the line below in your terminal (if your terminal is already in pyscript then use **cd pyscriptjs** instead)
|
||||
```
|
||||
cd pyscript/pyscriptjs
|
||||
```
|
||||
* Install the dependencies with the command below
|
||||
|
||||
```
|
||||
make setup
|
||||
```
|
||||
**NOTE**: If `make setup` gives a node/npm version required error then go to [troubleshooting](https://github.com/pyscript/pyscript/blob/main/TROUBLESHOOTING.md)
|
||||
|
||||
* You can also run the examples locally by running the command below in your terminal
|
||||
```
|
||||
make examples
|
||||
```
|
||||
* Run ***npm run dev*** to build and run the dev server. This will also watch for changes and rebuild when a file is saved.
|
||||
```
|
||||
npm run dev
|
||||
```
|
||||
**NOTE**: To access your local build paste `http://localhost:8080` into your browser
|
||||
|
||||
|
||||
Now that node and npm have both been updated `make setup` should work, and you can continue [setting up your local environment](#setting-up-your-local-environment) without problems (hopefully).
|
||||
|
||||
### Developing
|
||||
|
||||
* First, make sure you are using the latest version of the pyscript main branch
|
||||
|
||||
```
|
||||
git pull upstream main
|
||||
```
|
||||
|
||||
* Update your fork with the latest changes
|
||||
|
||||
```
|
||||
git push origin main
|
||||
```
|
||||
|
||||
* Activate the conda environment (this environment will contain all the necessary dependencies)
|
||||
|
||||
```
|
||||
conda activate pyscriptjs/env/
|
||||
```
|
||||
**NOTE**: We are assuming you are in the root folder. If you are in the pyscriptjs you can run `conda activate env/` instead.
|
||||
|
||||
* Install pre-commit (you only need to do this once)
|
||||
|
||||
```
|
||||
pre-commit install
|
||||
```
|
||||
**NOTE**: On first run, pre-commit installs a bunch of hooks that will be run when you commit changes to your branch - this will make sure that your code is following our style (it will also lint your code automatically).
|
||||
|
||||
* Create a branch for the issue that you want to work on
|
||||
|
||||
```
|
||||
git checkout -b <your branch name>
|
||||
```
|
||||
|
||||
* Work on your change
|
||||
|
||||
**NOTE**: If you are working on a python file, you may encounter linting issues when pre-commit runs. Pyscript uses [black](https://black.readthedocs.io/en/stable/) to fix any linting problems automatically. All you need to do is add the changes again and commit using your previous commit message (the previous one that failed didn't complete due to black formatting files).
|
||||
|
||||
* Run tests before pushing the changes
|
||||
|
||||
```
|
||||
make tests
|
||||
```
|
||||
|
||||
* When you make changes locally, double check that your contribution follows the PyScript formatting rules by running `npm run lint`. Note that in this case you're looking for the errors, <u>**NOT**</u> the warnings (Unless the warning is created by a local change). If an error is found by lint you should fix it <u>**before**</u> creating a pull request
|
||||
|
||||
#### Rebasing changes
|
||||
|
||||
Sometimes you might be asked to rebase main into your branch. You can do such by:
|
||||
|
||||
* Checkout into your main branch and pull the upstream changes
|
||||
|
||||
```
|
||||
git checkout main
|
||||
git pull upstream main
|
||||
```
|
||||
|
||||
* Checkout your branch and rebase on main
|
||||
|
||||
```
|
||||
git rebase -i main
|
||||
```
|
||||
|
||||
If you have conflicts, you must fix them by comparing yours and incoming changes. Your editor can probably help you with this, but do ask for help if you need it!
|
||||
|
||||
* Once all conflicts have been fixed
|
||||
|
||||
```
|
||||
git rebase --continue
|
||||
```
|
||||
**NOTE**: You may see more conflicts that you need to address until all are resolved.
|
||||
|
||||
* Force push the fixed conflicts
|
||||
|
||||
```
|
||||
git push -f origin <your branch name>
|
||||
```
|
||||
|
||||
|
||||
### Building the docs
|
||||
|
||||
To build the documentation locally first make sure you are in the `docs` directory.
|
||||
|
||||
You'll need `make` and `conda` installed in your machine. The rest of the environment should be automatically download and created for you once you use the command:
|
||||
|
||||
```
|
||||
make setup
|
||||
```
|
||||
|
||||
Use `conda activate $environment_name` to activate your environment.
|
||||
|
||||
To add new information to the documentation make sure you conform with PyScript's code of conduct and with the general principles of Diataxis. Don't worry about reading too much on it, just do your best to keep your contributions on the correct axis.
|
||||
|
||||
Write your documentation files using [Markedly Structured Text](https://myst-parser.readthedocs.io/en/latest/syntax/optional.html), which is very similar to vanilla Markdown but with some addons to create the documentation infrastructure.
|
||||
|
||||
Once done, initialize a server to check your work:
|
||||
|
||||
```
|
||||
make livehtml
|
||||
```
|
||||
|
||||
Visible here: http:///127.0.0.1:8000
|
||||
|
||||
## Places to start
|
||||
|
||||
If you would like to contribute to PyScript, but you aren't sure where to begin, here are some suggestions.
|
||||
If you would like to contribute to PyScript, but you aren't sure where to begin, here are some suggestions:
|
||||
|
||||
* **Read over the existing documentation.** Are there things missing, or could they be clearer? Make some changes/additions to those documents.
|
||||
* **Review the open issues.** Are they clear? Can you reproduce them? You can add comments, clarifications, or additions to those issues. If you think you have an idea of how to address the issue, submit a fix!
|
||||
* **Look over the open pull requests.** Do you have comments or suggestions for the proposed changes? Add them.
|
||||
* **Check out the examples.** Is there a use case that would be good to have sample code for? Create an example for it.
|
||||
- **Read over the existing documentation.** Are there things missing, or could they be clearer? Make some changes/additions to those documents.
|
||||
- **Review the open issues.** Are they clear? Can you reproduce them? You can add comments, clarifications, or additions to those issues. If you think you have an idea of how to address the issue, submit a fix!
|
||||
- **Look over the open pull requests.** Do you have comments or suggestions for the proposed changes? Add them.
|
||||
- **Check out the examples.** Is there a use case that would be good to have sample code for? Create an example for it.
|
||||
|
||||
# Submitting a change
|
||||
## Setting up your local environment and developing
|
||||
|
||||
All contributions must be licensed Apache 2.0, and all files must have a copy of the boilerplate license comment (can be copied from an existing file).
|
||||
If you would like to contribute to PyScript, you will need to set up a local development environment. The [following instructions](https://pyscript.github.io/docs/latest/development/setting-up-environment.html) will help you get started.
|
||||
|
||||
To create a change for PyScript, you can follow the process described [here](https://docs.github.com/en/get-started/quickstart/contributing-to-projects).
|
||||
|
||||
* Follow the steps in [setting your local environment](#setting-up-your-local-environment) and [developing](#developing)
|
||||
* Make the changes you would like (don't forget to test them with `make test`)
|
||||
* Open a pull request back to the PyScript project and address any comments/questions from the maintainers and other contributors.
|
||||
You can also read about PyScript's [development process](https://pyscript.github.io/docs/latest/development/developing.html) to learn how to contribute code to PyScript, how to run tests and what's the PR etiquette of the community!
|
||||
|
||||
## License terms for contributions
|
||||
|
||||
This Project welcomes contributions, suggestions, and feedback. All contributions, suggestions, and feedback you submitted are accepted under the [Apache 2.0](./LICENSE) license. You represent that if you do not own copyright in the code that you have the authority to submit it under the [Apache 2.0](./LICENSE) license. All feedback, suggestions, or contributions are not confidential.
|
||||
|
||||
|
||||
## Becoming a maintainer
|
||||
|
||||
Contributors are invited to be maintainers of the project by demonstrating good decision making in their contributions, a commitment to the goals of the project, and consistent adherence to the [code of conduct](https://github.com/pyscript/governance/blob/main/CODE-OF-CONDUCT.md). New maintainers are invited by a 3/4 vote of the existing maintainers.
|
||||
@@ -217,5 +76,6 @@ Contributors are invited to be maintainers of the project by demonstrating good
|
||||
The Project abides by the Organization's [trademark policy](https://github.com/pyscript/governance/blob/main/TRADEMARKS.md).
|
||||
|
||||
---
|
||||
|
||||
Part of MVG-0.1-beta.
|
||||
Made with love by GitHub. Licensed under the [CC-BY 4.0 License](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
|
||||
@@ -41,5 +41,6 @@ Any names, trademarks, logos, or goodwill developed by and associated with the P
|
||||
Amendments to this governance policy may be made by affirmative vote of 2/3 of all Maintainers, with approval by the Organization's Steering Committee.
|
||||
|
||||
---
|
||||
|
||||
Part of MVG-0.1-beta.
|
||||
Made with love by GitHub. Licensed under the [CC-BY 4.0 License](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
|
||||
@@ -9,14 +9,16 @@ This document lists the Maintainers of the Project. Maintainers may be added onc
|
||||
| Philipp Rudiger | Anaconda, Inc |
|
||||
| Peter Wang | Anaconda, Inc |
|
||||
| Kevin Goldsmith | Anaconda, Inc |
|
||||
| Mariana Meireles | Anaconda, Inc |
|
||||
| Mariana Meireles | |
|
||||
| Nicholas H.Tollervey | Anaconda, Inc |
|
||||
| Madhur Tandon | Anaconda, Inc |
|
||||
| Ted Patrick | Anaconda, Inc |
|
||||
| Jeff Glass | --- |
|
||||
| --- | --- |
|
||||
| Jeff Glass | |
|
||||
| Paul Everitt | |
|
||||
| Fabio Rosado | Anaconda, Inc |
|
||||
| Andrea Giammarchi | Anaconda, Inc |
|
||||
|
||||
______________________________________________________________________
|
||||
---
|
||||
|
||||
Part of MVG-0.1-beta.
|
||||
Made with love by GitHub. Licensed under the [CC-BY 4.0 License](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
|
||||
92
Makefile
Normal file
92
Makefile
Normal file
@@ -0,0 +1,92 @@
|
||||
MIN_NODE_VER := 20
|
||||
MIN_NPM_VER := 6
|
||||
MIN_PY3_VER := 8
|
||||
NODE_VER := $(shell node -v | cut -d. -f1 | sed 's/^v\(.*\)/\1/')
|
||||
NPM_VER := $(shell npm -v | cut -d. -f1)
|
||||
PY3_VER := $(shell python3 -c "import sys;t='{v[1]}'.format(v=list(sys.version_info[:2]));print(t)")
|
||||
PY_OK := $(shell python3 -c "print(int($(PY3_VER) >= $(MIN_PY3_VER)))")
|
||||
|
||||
all:
|
||||
@echo "\nThere is no default Makefile target right now. Try:\n"
|
||||
@echo "make setup - check your environment and install the dependencies."
|
||||
@echo "make clean - clean up auto-generated assets."
|
||||
@echo "make build - build PyScript."
|
||||
@echo "make precommit-check - run the precommit checks (run eslint)."
|
||||
@echo "make test-integration - run all integration tests sequentially."
|
||||
@echo "make fmt - format the code."
|
||||
@echo "make fmt-check - check the code formatting.\n"
|
||||
|
||||
.PHONY: check-node
|
||||
check-node:
|
||||
@if [ $(NODE_VER) -lt $(MIN_NODE_VER) ]; then \
|
||||
echo "\033[0;31mBuild requires Node $(MIN_NODE_VER).x or higher: $(NODE_VER) detected.\033[0m"; \
|
||||
false; \
|
||||
fi
|
||||
|
||||
.PHONY: check-npm
|
||||
check-npm:
|
||||
@if [ $(NPM_VER) -lt $(MIN_NPM_VER) ]; then \
|
||||
echo "\033[0;31mBuild requires Node $(MIN_NPM_VER).x or higher: $(NPM_VER) detected.\033[0m"; \
|
||||
false; \
|
||||
fi
|
||||
|
||||
.PHONY: check-python
|
||||
check-python:
|
||||
@if [ $(PY_OK) -eq 0 ]; then \
|
||||
echo "\033[0;31mRequires Python 3.$(MIN_PY3_VER).x or higher: 3.$(PY3_VER) detected.\033[0m"; \
|
||||
false; \
|
||||
fi
|
||||
|
||||
# Check the environment, install the dependencies.
|
||||
setup: check-node check-npm check-python
|
||||
cd pyscript.core && npm install && cd ..
|
||||
ifeq ($(VIRTUAL_ENV),)
|
||||
echo "\n\n\033[0;31mCannot install Python dependencies. Your virtualenv is not activated.\033[0m"
|
||||
false
|
||||
else
|
||||
python -m pip install -r requirements.txt
|
||||
playwright install
|
||||
endif
|
||||
|
||||
# Clean up generated assets.
|
||||
clean:
|
||||
find . -name \*.py[cod] -delete
|
||||
rm -rf $(env) *.egg-info
|
||||
rm -rf .pytest_cache .coverage coverage.xml
|
||||
|
||||
# Build PyScript.
|
||||
build:
|
||||
cd pyscript.core && npx playwright install && npm run build
|
||||
|
||||
# Run the precommit checks (run eslint).
|
||||
precommit-check:
|
||||
pre-commit run --all-files
|
||||
|
||||
# Run all integration tests sequentially.
|
||||
test-integration:
|
||||
mkdir -p test_results
|
||||
pytest -vv $(ARGS) pyscript.core/tests/integration/ --log-cli-level=warning --junitxml=test_results/integration.xml
|
||||
|
||||
# Run all integration tests in parallel.
|
||||
test-integration-parallel:
|
||||
mkdir -p test_results
|
||||
pytest --numprocesses auto -vv $(ARGS) pyscript.core/tests/integration/ --log-cli-level=warning --junitxml=test_results/integration.xml
|
||||
|
||||
# Format the code.
|
||||
fmt: fmt-py
|
||||
@echo "Format completed"
|
||||
|
||||
# Check the code formatting.
|
||||
fmt-check: fmt-py-check
|
||||
@echo "Format check completed"
|
||||
|
||||
# Format Python code.
|
||||
fmt-py:
|
||||
black -l 88 --skip-string-normalization .
|
||||
isort --profile black .
|
||||
|
||||
# Check the format of Python code.
|
||||
fmt-py-check:
|
||||
black -l 88 --check .
|
||||
|
||||
.PHONY: $(MAKECMDGOALS)
|
||||
67
README.md
67
README.md
@@ -4,45 +4,72 @@
|
||||
|
||||
### Summary
|
||||
|
||||
PyScript is a framework that allows users to create rich Python applications in the browser using HTML's interface and the power of [Pyodide](https://pyodide.org/en/stable/), [WASM](https://webassembly.org/), and modern web technologies.
|
||||
PyScript is a framework that allows users to create rich Python applications in the browser using HTML's interface and the power of [Pyodide](https://pyodide.org/en/stable/), [MicroPython](https://micropython.org/) and [WASM](https://webassembly.org/), and modern web technologies.
|
||||
|
||||
To get started see the [getting started tutorial](docs/tutorials/getting-started.md).
|
||||
To get started see the [Beginning PyScript tutorial](https://docs.pyscript.net/latest/beginning-pyscript/).
|
||||
|
||||
For examples see [here](examples).
|
||||
For examples see [here](https://pyscript.com/@examples).
|
||||
|
||||
Other useful resources:
|
||||
|
||||
- The [official technical docs](https://docs.pyscript.net/).
|
||||
- Our current [Home Page](https://pyscript.net/) on the web.
|
||||
- A free-to-use [online editor](https://pyscript.com/) for trying PyScript.
|
||||
- Our community [Discord Channel](https://discord.gg/BYB2kvyFwm), to keep in touch .
|
||||
|
||||
Every Tuesday at 15:30 UTC there is the _PyScript Community Call_ on zoom, where we can talk about PyScript development in the open. Most of the maintainers regularly participate in the call, and everybody is welcome to join.
|
||||
|
||||
Every other Thursday at 16:00 UTC there is the _PyScript FUN_ call: this is a call in which everybody is encouraged to show what they did with PyScript.
|
||||
|
||||
For more details on how to join the calls and up to date schedule, consult the official calendar:
|
||||
|
||||
- [Google calendar](https://calendar.google.com/calendar/u/0/embed?src=d3afdd81f9c132a8c8f3290f5cc5966adebdf61017fca784eef0f6be9fd519e0@group.calendar.google.com&ctz=UTC) in UTC time;
|
||||
- [iCal format](https://calendar.google.com/calendar/ical/d3afdd81f9c132a8c8f3290f5cc5966adebdf61017fca784eef0f6be9fd519e0%40group.calendar.google.com/public/basic.ics).
|
||||
|
||||
### Longer Version
|
||||
|
||||
PyScript is a meta project that aims to combine multiple open technologies into a framework that allows users to create sophisticated browser applications with Python. It integrates seamlessly with the way the DOM works in the browser and allows users to add Python logic in a way that feels natural both to web and Python developers.
|
||||
|
||||
## Try PyScript
|
||||
|
||||
To try PyScript, import the appropriate pyscript files into the ```<head>``` tag of your html page with:
|
||||
To try PyScript, import the appropriate pyscript files into the `<head>` tag of your html page:
|
||||
|
||||
```html
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://pyscript.net/releases/2023.11.2/core.css"
|
||||
/>
|
||||
<script
|
||||
type="module"
|
||||
src="https://pyscript.net/releases/2023.11.2/core.js"
|
||||
></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="py" terminal>
|
||||
from pyscript import display
|
||||
display("Hello World!") # this goes to the DOM
|
||||
print("Hello terminal") # this goes to the terminal
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
You can then use PyScript components in your html page. PyScript currently implements the following elements:
|
||||
|
||||
* `<py-script>`: can be used to define python code that is executable within the web page. The element itself is not rendered to the page and is only used to add logic
|
||||
* `<py-repl>`: creates a REPL component that is rendered to the page as a code editor and allows users to write executable code
|
||||
You can then use PyScript components in your html page. PyScript currently offers various ways of running Python code:
|
||||
|
||||
Check out the [the examples directory](examples) folder for more examples on how to use it, all you need to do is open them in Chrome.
|
||||
- `<script type="py">`: can be used to define python code that is executable within the web page.
|
||||
- `<script type="py" src="hello.py">`: same as above, but the python source is fetched from the given URL.
|
||||
- `<script type="py" terminal>`: same as above, but also creates a terminal where to display stdout and stderr (e.g., the output of `print()`); `input()` does not work.
|
||||
- `<script type="py" terminal worker>`: run Python inside a web worker: the terminal is fully functional and `input()` works.
|
||||
- `<py-script>`: same as `<script type="py">`, but it is not recommended because if the code contains HTML tags, they could be parsed wrongly.
|
||||
- `<script type="mpy">`: same as above but use MicroPython instead of Python.
|
||||
|
||||
Check out the [official docs](https://docs.pyscript.net/) for more detailed documentation.
|
||||
|
||||
## How to Contribute
|
||||
|
||||
Read the [contributing guide](CONTRIBUTING.md) to learn about our development process, reporting bugs and improvements, creating issues and asking questions.
|
||||
|
||||
## Resources
|
||||
|
||||
* [Discussion board](https://community.anaconda.cloud/c/tech-topics/pyscript)
|
||||
* [Home Page](https://pyscript.net/)
|
||||
* [Blog Post](https://engineering.anaconda.com/2022/04/welcome-pyscript.html)
|
||||
|
||||
## Notes
|
||||
|
||||
* This is an extremely experimental project, so expect things to break!
|
||||
* PyScript has been only tested on Chrome at the moment.
|
||||
Check out the [developing process](https://pyscript.github.io/docs/latest/contributing) documentation for more information on how to setup your development environment.
|
||||
|
||||
## Governance
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
This page is meant for troubleshooting common problems with PyScript.
|
||||
|
||||
## Table of contents:
|
||||
* [Make Setup](#make-setup)
|
||||
|
||||
- [Make Setup](#make-setup)
|
||||
|
||||
## Make setup
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
CONDA_ENV ?= _env
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
env := $(CONDA_ENV)
|
||||
conda_run := conda run -p $(env)
|
||||
|
||||
setup:
|
||||
@if [ -z "$${CONDA_SHLVL:+x}" ]; then echo "Conda is not installed." && exit 1; fi
|
||||
$(CONDA_EXE) env $(shell [ -d $(env) ] && echo update || echo create) -p $(env) --file environment.yml
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)
|
||||
|
||||
clean-all: clean
|
||||
rm -rf $(env) *.egg-info
|
||||
|
||||
shell:
|
||||
@export CONDA_ENV_PROMPT='<{name}>'
|
||||
@echo 'conda activate $(env)'
|
||||
|
||||
htmlserve:
|
||||
@echo 'visit docs at http://localhost:8080'
|
||||
python -m http.server -d "$(BUILDDIR)/html/" 8080
|
||||
|
||||
livehtml:
|
||||
sphinx-autobuild "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
|
||||
.PHONY: help Makefile setup clean clean-all shell
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
@@ -1,31 +0,0 @@
|
||||
# PyScript documentation
|
||||
|
||||
Welcome to the PyScript documentation directory, where you can find
|
||||
and contribute to discussions around PyScript and related topics.
|
||||
|
||||
## Getting started
|
||||
|
||||
Before you start contributing to the documentation, it's worthwhile to
|
||||
take a look at the general contributing guidelines for the PyScript project. You can find these guidelines here
|
||||
[Contributing Guidelines](https://github.com/pyscript/pyscript/blob/main/CONTRIBUTING.md)
|
||||
|
||||
## Documentation Principles
|
||||
|
||||
The PyScript documentation is based on a documentation framework called [Diátaxis](https://diataxis.fr/). This framework helps to solve the problem of structure in technical documentation and identifies four modes of documentation - **tutorials, how-to guides, technical reference and explanation**. Each one of these modes answers to a different user need, fulfills a different purpose and requires a different approach to its creation.
|
||||
|
||||
The picture below gives a good visual representation of that separation of concerns:
|
||||
|
||||

|
||||
|
||||
So, please keep that in mind when contributing to the project documentation. For more information on, make sure to check [their website](https://diataxis.fr/).
|
||||
|
||||
### Setup
|
||||
|
||||
The `docs` directory in the pyscript repository contains a
|
||||
[Sphinx](https://www.sphinx-doc.org/) documentation project. Sphinx is a system
|
||||
that takes plaintext files containing documentation written in Markdown, along with
|
||||
static files like templates and themes, to build the static end result.
|
||||
|
||||
### Build
|
||||
|
||||
To learn how to build the docs, head over the [CONTRIBUTING](../CONTRIBUTING.md) page.
|
||||
44
docs/_static/examples/what-is-pyscript.html
vendored
44
docs/_static/examples/what-is-pyscript.html
vendored
@@ -1,44 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<style>
|
||||
.pulse {
|
||||
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: .2;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<py-env>
|
||||
- numpy
|
||||
- matplotlib
|
||||
</py-env>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Let's plot random numbers</h1>
|
||||
<div id="plot">
|
||||
<div class="pulse" >
|
||||
<p style='font-family: monospace sans-serif;'><big><big><big><big>❰py❱</big></big></big></big></p>
|
||||
</div>
|
||||
</div>
|
||||
<py-script>
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
x = np.random.randn(1000)
|
||||
y = np.random.randn(1000)
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
ax.scatter(x, y)
|
||||
pyscript.write('plot', fig)
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
docs/_static/fonts/Hack-Bold.woff
vendored
BIN
docs/_static/fonts/Hack-Bold.woff
vendored
Binary file not shown.
BIN
docs/_static/fonts/Hack-BoldItalic.woff
vendored
BIN
docs/_static/fonts/Hack-BoldItalic.woff
vendored
Binary file not shown.
BIN
docs/_static/fonts/Hack-Italic.woff
vendored
BIN
docs/_static/fonts/Hack-Italic.woff
vendored
Binary file not shown.
BIN
docs/_static/fonts/Hack-Regular.woff
vendored
BIN
docs/_static/fonts/Hack-Regular.woff
vendored
Binary file not shown.
BIN
docs/_static/images/avatar.jpg
vendored
BIN
docs/_static/images/avatar.jpg
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB |
1
docs/_static/redirect.html
vendored
1
docs/_static/redirect.html
vendored
@@ -1 +0,0 @@
|
||||
<html><head><meta http-equiv="refresh" content="0; URL='/latest/'" /></head><body></body></html>
|
||||
@@ -1 +0,0 @@
|
||||
../../../MAINTAINERS.md
|
||||
@@ -1 +0,0 @@
|
||||
../../../GOVERNANCE.md
|
||||
@@ -1,12 +0,0 @@
|
||||
# Concepts
|
||||
|
||||
This section contains various topics that are higher-level and useful to know.
|
||||
|
||||
```{toctree}
|
||||
---
|
||||
maxdepth: 2
|
||||
glob:
|
||||
---
|
||||
what-is-pyscript
|
||||
governance/*
|
||||
```
|
||||
@@ -1,33 +0,0 @@
|
||||
# What is PyScript?
|
||||
|
||||
The PyScript library provides HTML tags for embedding and executing Python code in your browser. PyScript is built using [Pyodide](https://pyodide.org/en/stable/), the WebAssembly port of CPython, which is compiled using [Emscripten](https://emscripten.org/).
|
||||
|
||||
PyScript turns the browser into a code deployment tool that anyone can learn to use.
|
||||
|
||||
## Example
|
||||
|
||||
In this example, we are using the `<py-script>` HTML tag to generate a Matplotlib figure and display it as an image.
|
||||
Click **Preview** to see the rendered HTML.
|
||||
|
||||
To try it in your browser, copy the code below into an online HTML editor like W3School's [Tryit Editor](https://www.w3schools.com/html/tryit.asp?filename=tryhtml_default_default), which allows you to modify, run, and even save your code. Watch the video below to see it in action!
|
||||
|
||||
```{youtube} ZtC7TCt_LhU
|
||||
```
|
||||
|
||||
::::{tab-set}
|
||||
:::{tab-item} HTML Source
|
||||
|
||||
```{literalinclude} ../_static/examples/what-is-pyscript.html
|
||||
---
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::{tab-item} Preview
|
||||
|
||||
```{raw} html
|
||||
<iframe height="600px" width="100%" scrolling="auto" frameborder="0" src="../_static/examples/what-is-pyscript.html"></iframe>
|
||||
```
|
||||
|
||||
:::
|
||||
::::
|
||||
103
docs/conf.py
103
docs/conf.py
@@ -1,103 +0,0 @@
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
import os
|
||||
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = "PyScript"
|
||||
copyright = "(c) 2022, Anaconda, Inc."
|
||||
author = "Anaconda, Inc."
|
||||
language = "en"
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
"myst_parser",
|
||||
"sphinx_copybutton",
|
||||
"sphinx_design",
|
||||
"sphinx_togglebutton",
|
||||
"sphinx_sitemap",
|
||||
"sphinxemoji.sphinxemoji",
|
||||
"sphinxcontrib.youtube",
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ["_templates"]
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "_env", "README.md"]
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = "pydata_sphinx_theme"
|
||||
|
||||
html_logo = "_static/images/avatar.jpg"
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ["_static"]
|
||||
# html_css_files = ["styles/custom.css"]
|
||||
|
||||
html_baseurl = os.environ.get("SPHINX_HTML_BASE_URL", "http://127.0.0.1:8000/")
|
||||
sitemap_locales = [None]
|
||||
sitemap_url_scheme = "{link}"
|
||||
|
||||
html_extra_path = ["robots.txt"]
|
||||
|
||||
html_theme_options = {
|
||||
"github_url": "https://github.com/pyscript/pyscript",
|
||||
"twitter_url": "https://twitter.com/pyscript_dev",
|
||||
"icon_links_label": "Quick Links",
|
||||
# "google_analytics_id": "G-XXXXXXXXXX",
|
||||
"use_edit_page_button": True,
|
||||
"show_nav_level": 2,
|
||||
"external_links": [
|
||||
# {"name": "GitHub repo", "url": "https://github.com/pyscript/pyscript"},
|
||||
],
|
||||
}
|
||||
|
||||
html_context = {
|
||||
"default_mode": "dark",
|
||||
"pygment_light_style": "tango",
|
||||
"pygment_dark_style": "native",
|
||||
"github_user": "pyscript",
|
||||
"github_repo": "pyscript",
|
||||
"github_version": "main",
|
||||
"doc_path": "docs",
|
||||
}
|
||||
|
||||
|
||||
myst_enable_extensions = [
|
||||
"dollarmath",
|
||||
"amsmath",
|
||||
"deflist",
|
||||
"html_admonition",
|
||||
"html_image",
|
||||
"colon_fence",
|
||||
"smartquotes",
|
||||
"replacements",
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
channels:
|
||||
- conda-forge
|
||||
- defaults
|
||||
dependencies:
|
||||
- python=3.9
|
||||
- pip=20.2.2
|
||||
- Sphinx=4.5.0
|
||||
- myst-parser=0.17.2
|
||||
- pydata-sphinx-theme
|
||||
- sphinx-copybutton
|
||||
- sphinx-design
|
||||
- sphinx-togglebutton
|
||||
|
||||
- pip:
|
||||
- sphinxemoji
|
||||
- sphinx-sitemap
|
||||
- sphinx-autobuild
|
||||
- sphinxcontrib-youtube
|
||||
@@ -1,210 +0,0 @@
|
||||
# How to make HTTP requests using `PyScript`, in pure Python
|
||||
|
||||
[Pyodide](https://pyodide.org), the runtime that underlies `PyScript`, does not have the `requests` module
|
||||
(or other similar modules) available by default, which are traditionally used to make HTTP requests in Python.
|
||||
However, it is possible to make HTTP requests in Pyodide using the modern `JavaScript` `fetch` API
|
||||
([docs](https://developer.mozilla.org/en-US/docs/Web/API/fetch)). This example shows how to make common HTTP request
|
||||
(GET, POST, PUT, DELETE) to an API, using only Python code! We will use asynchronous functions with
|
||||
async/await syntax, as concurrent code is preferred for HTTP requests.
|
||||
|
||||
The purpose of this guide is not to teach the basics of HTTP requests, but to show how to make them
|
||||
from `PyScript` using Python, since currently, the common tools such as `requests` and `httpx` are not available.
|
||||
|
||||
## Fetch
|
||||
|
||||
The `fetch` API is a modern way to make HTTP requests. It is available in all modern browsers, and in Pyodide.
|
||||
|
||||
Although there are two ways to use `fetch`, 1) using `JavaScript` from `PyScript`, and 2) using Pyodide's Python wrapper,
|
||||
`Pyodide.http.pyfetch`, this example will only show how to use the Python wrapper. Still, the
|
||||
[fetch documentation](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters) is a useful reference, as its
|
||||
parameters can be called from Python using the `pyfetch` wrapper.
|
||||
|
||||
## Pyodide.http, pyfetch, and FetchResponse
|
||||
|
||||
[Pyodide.http module](https://pyodide.org/en/stable/usage/api/python-api/http.html#module-pyodide.http) is a Python API
|
||||
for dealing with HTTP requests. It provides the `pyfetch` function as a wrapper for the `fetch` API,
|
||||
which returns a `FetchResponse` object whenever a request is made. Extra keyword arguments can be passed to `pyfetch`
|
||||
which will be passed to the `fetch` API.
|
||||
|
||||
The returned object `FetchResponse` has familiar methods and properties
|
||||
for dealing with the response, such as `json()` or `status`. See the
|
||||
[FetchResponse documentation](https://pyodide.org/en/stable/usage/api/python-api/http.html#pyodide.http.FetchResponse)
|
||||
for more information.
|
||||
|
||||
# Example
|
||||
We will make async HTTP requests to [JSONPlaceholder](https://jsonplaceholder.typicode.com/)'s fake API using `pyfetch`.
|
||||
First we write a helper function in pure Python that makes a request and returns the response. This function
|
||||
makes it easier to make specific types of requests with the most common parameters.
|
||||
|
||||
## Python convenience function
|
||||
|
||||
```python
|
||||
from pyodide.http import pyfetch, FetchResponse
|
||||
from typing import Optional, Any
|
||||
|
||||
async def request(url: str, method: str = "GET", body: Optional[str] = None,
|
||||
headers: Optional[dict[str, str]] = None, **fetch_kwargs: Any) -> FetchResponse:
|
||||
"""
|
||||
Async request function. Pass in Method and make sure to await!
|
||||
Parameters:
|
||||
url: str = URL to make request to
|
||||
method: str = {"GET", "POST", "PUT", "DELETE"} from `JavaScript` global fetch())
|
||||
body: str = body as json string. Example, body=json.dumps(my_dict)
|
||||
headers: dict[str, str] = header as dict, will be converted to string...
|
||||
Example, headers=json.dumps({"Content-Type": "application/json"})
|
||||
fetch_kwargs: Any = any other keyword arguments to pass to `pyfetch` (will be passed to `fetch`)
|
||||
Return:
|
||||
response: pyodide.http.FetchResponse = use with .status or await.json(), etc.
|
||||
"""
|
||||
kwargs = {"method": method, "mode": "cors"} # CORS: https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
|
||||
if body and method not in ["GET", "HEAD"]:
|
||||
kwargs["body"] = body
|
||||
if headers:
|
||||
kwargs["headers"] = headers
|
||||
kwargs.update(fetch_kwargs)
|
||||
|
||||
response = await pyfetch(url, **kwargs)
|
||||
return response
|
||||
```
|
||||
This function is a wrapper for `pyfetch`, which is a wrapper for the `fetch` API. It is a coroutine function,
|
||||
so it must be awaited. It also has type hints, which are not required, but are useful for IDEs and other tools.
|
||||
The basic idea is that the `PyScript` will import and call this function, then await the response. Therefore,
|
||||
the script containing this function must be importable by `PyScript`.
|
||||
|
||||
For this example, we will name the file containing the Python code `request.py` and place it in the same directory as the file
|
||||
containing the html code, which is described below.
|
||||
|
||||
## `PyScript` HTML code
|
||||
|
||||
In this How-to, the HTML code is split into separate code blocks to enable context highlighting (coloring of the Python
|
||||
code inside the html code block), but in reality it is all in the same file. The first part is a bare bones `PyScript`
|
||||
html page, using the [community examples](https://github.com/pyscript/pyscript-collective/) set-up. The second part is
|
||||
the actual Python code for HTTP requests, which is wrapped in `<py-script>` tags, while the third block has the
|
||||
concluding html code.
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
|
||||
<title>GET, POST, PUT, DELETE example</title>
|
||||
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<link rel="stylesheet" href="../build/pyscript.css" />
|
||||
|
||||
<script defer src="../build/pyscript.js"></script>
|
||||
<py-env>
|
||||
- paths:
|
||||
- /request.py
|
||||
</py-env>
|
||||
</head>
|
||||
|
||||
<body><p>
|
||||
Hello world request example! <br>
|
||||
Here is the output of your request:
|
||||
</p>
|
||||
<py-script>
|
||||
```
|
||||
```python
|
||||
import asyncio # important!!
|
||||
import json
|
||||
from request import request # import our request function.
|
||||
|
||||
baseurl = "https://jsonplaceholder.typicode.com/"
|
||||
|
||||
# GET
|
||||
headers = {"Content-type": "application/json"}
|
||||
response = await request(baseurl+"posts/2", method="GET", headers=headers)
|
||||
print(f"GET request=> status:{response.status}, json:{await response.json()}")
|
||||
|
||||
# POST
|
||||
body = json.dumps({"title": "test_title", "body": "test body", "userId": 1})
|
||||
new_post = await request(baseurl+"posts", body=body, method="POST", headers=headers)
|
||||
print(f"POST request=> status:{new_post.status}, json:{await new_post.json()}")
|
||||
|
||||
# PUT
|
||||
body = json.dumps({"id": 1, "title": "test_title", "body": "test body", "userId": 2})
|
||||
new_post = await request(baseurl+"posts/1", body=body, method="PUT", headers=headers)
|
||||
print(f"PUT request=> status:{new_post.status}, json:{await new_post.json()}")
|
||||
|
||||
# DELETE
|
||||
new_post = await request(baseurl+"posts/1", method="DELETE", headers=headers)
|
||||
print(f"DELETE request=> status:{new_post.status}, json:{await new_post.json()}")
|
||||
```
|
||||
```html
|
||||
</py-script>
|
||||
|
||||
<div>
|
||||
<p>
|
||||
You can also use other methods. See fetch documentation: <br>
|
||||
https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
See pyodide documentation for what to do with a FetchResponse object: <br>
|
||||
https://pyodide.org/en/stable/usage/api/python-api.html#pyodide.http.FetchResponse
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Explanation
|
||||
### `py-env` tag for importing our Python code
|
||||
The very first thing to notice is the `py-env` tag. This tag is used to import Python files into the `PyScript`.
|
||||
In this case, we are importing the `request.py` file, which contains the `request` function we wrote above.
|
||||
|
||||
### `py-script` tag for making async HTTP requests.
|
||||
Next, the `py-script` tag contains the actual Python code where we import `asyncio` and `json`,
|
||||
which are required or helpful for the `request` function.
|
||||
The `# GET`, `# POST`, `# PUT`, `# DELETE` blocks show examples of how to use the `request` function to make basic
|
||||
HTTP requests. The `await` keyword is required not only for the `request` function, but also for certain methods of the
|
||||
`FetchResponse` object, such as `json()`, meaning that the code is asynchronous and slower requests will not block the
|
||||
faster ones.
|
||||
|
||||
### HTTP Requests
|
||||
HTTP requests are a very common way to communicate with a server. They are used for everything from getting data from
|
||||
a database, to sending emails, to authorization, and more. Due to safety concerns, files loaded from the
|
||||
local file system are not accessible by `PyScript`. Therefore, the proper way to load data into `PyScript` is also
|
||||
through HTTP requests.
|
||||
|
||||
In our example, we show how to pass in a request `body`, `headers`, and specify the request `method`, in order to make
|
||||
`GET`, `POST`, `PUT`, and `DELETE` requests, although methods such as `PATCH` are also available. Additional
|
||||
parameters for the `fetch` API are also available, which can be specified as keyword arguments passed to our helper
|
||||
function or to `pyfetch`. See the
|
||||
[fetch documentation](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters) for more information.
|
||||
HTTP requests are defined by standards-setting bodies in [RFC 1945](https://www.rfc-editor.org/info/rfc1945) and
|
||||
[RFC 9110](https://www.rfc-editor.org/info/rfc9110).
|
||||
|
||||
# Conclusion
|
||||
This tutorial demonstrates how to make HTTP requests using `pyfetch` and the `FetchResponse` objects. Importing Python
|
||||
code/files into the `PyScript` using the `py-env` tag is also covered.
|
||||
|
||||
Although a simple example, the principals here can be used to create complex web applications inside of `PyScript`,
|
||||
or load data into `PyScript` for use by an application, all served as a static HTML page, which is pretty amazing!
|
||||
|
||||
|
||||
# API Quick Reference
|
||||
## pyodide.http.pyfetch
|
||||
### Usage
|
||||
```python
|
||||
await pyodide.http.pyfetch(url: str, **kwargs: Any) -> FetchResponse
|
||||
```
|
||||
Use `pyfetch` to make HTTP requests in `PyScript`. This is a wrapper around the `fetch` API. Returns a `FetchResponse`.
|
||||
|
||||
### [`pyfetch` Docs.](https://pyodide.org/en/stable/usage/api/python-api/http.html#pyodide.http.pyfetch)
|
||||
|
||||
## pyodide.http.FetchResponse
|
||||
### Usage
|
||||
```python
|
||||
response: pyodide.http.FetchResponse = await <pyfetch call>
|
||||
status = response.status
|
||||
json = await response.json()
|
||||
```
|
||||
Class for handling HTTP responses. This is a wrapper around the `JavaScript` fetch `Response`. Contains common (async)
|
||||
methods and properties for handling HTTP responses, such as `json()`, `url`, `status`, `headers`, etc.
|
||||
|
||||
### [`FetchResponse` Docs.](https://pyodide.org/en/stable/usage/api/python-api/http.html#pyodide.http.FetchResponse)
|
||||
@@ -1,19 +0,0 @@
|
||||
# How-to guides
|
||||
|
||||
Welcome to the how-to documentation section for PyScript. If you've already
|
||||
gained some experience with PyScript before and just need practical guides
|
||||
to get your ideas realized, you can learn step by step how to use PyScript here.
|
||||
|
||||
```{note}
|
||||
Please head over to the [tutorials](../tutorials/index.md) section if you're only getting started.
|
||||
```
|
||||
|
||||
```{toctree}
|
||||
---
|
||||
maxdepth: 2
|
||||
glob:
|
||||
caption: 'Contents:'
|
||||
---
|
||||
passing-objects
|
||||
http-requests
|
||||
```
|
||||
@@ -1,140 +0,0 @@
|
||||
# How to Pass Objects from PyScript to Javascript (and Vice Versa)
|
||||
|
||||
[Pyodide](https://pyodide.org), the runtime that underlies PyScript, does a lot of work under the hood to translate objects between Python and JavaScript. This allows code in one language to access objects defined in the other.
|
||||
|
||||
This guide discusses how to pass objects between JavaScript and Python within PyScript. For more details on how Pyodide handles translating and proxying objects between the two languages, see the [Pyodide Type Translations Page](https://pyodide.org/en/stable/usage/type-conversions.html).
|
||||
|
||||
For our purposes, an 'object' is anything that can be bound to a variable (a number, string, object, [function](https://developer.mozilla.org/en-US/docs/Glossary/First-class_Function), etc).
|
||||
|
||||
## JavaScript to PyScript
|
||||
|
||||
We can use the syntax `from js import ...` to import JavaScript objects directly into PyScript. Simple JavaScript objects are converted to equivalent Python types; these are called [implicit conversions](https://pyodide.org/en/stable/usage/type-conversions.html#implicit-conversions). More complicated objects are wrapped in [JSProxy](https://pyodide.org/en/stable/usage/type-conversions.html) objects to make them behave like Python objects.
|
||||
|
||||
`import js` and `from js import ...` [in Pyodide](https://pyodide.org/en/stable/usage/type-conversions.html#type-translations-using-js-obj-from-py) get objects from the [JavaScript globalThis scope](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis), so keep the[ rules of JavaScript variable scoping](https://www.freecodecamp.org/news/var-let-and-const-whats-the-difference/) in mind.
|
||||
|
||||
```html
|
||||
<script>
|
||||
name = "Guido" //A JS variable
|
||||
|
||||
// Define a JS Function
|
||||
function addTwoNumbers(x, y){
|
||||
return x + y;
|
||||
}
|
||||
</script>
|
||||
```
|
||||
```python
|
||||
<py-script>
|
||||
# Import and use JS function and variable into Python
|
||||
from js import name, addTwoNumbers
|
||||
|
||||
print(f"Hello {name}")
|
||||
print("Adding 1 and 2 in Javascript: " + str(addTwoNumbers(1, 2)))
|
||||
</py-script>
|
||||
```
|
||||
|
||||
## PyScript to JavaScript
|
||||
|
||||
Since [PyScript doesn't export its instance of Pyodide](https://github.com/pyscript/pyscript/issues/494) and only one instance of Pyodide can be running in a browser window at a time, there isn't currently a way for Javascript to access Objects defined inside PyScript tags "directly".
|
||||
|
||||
We can work around this limitation using [JavaScript's eval() function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval), which executes a string as code much like [Python's eval()](https://docs.python.org/3/library/functions.html#eval). First, we create a JS function `createObject` which takes an object and a string, then uses `eval()` to create a variable named after the string and bind it to that object. By calling this function from PyScript (where we have access to the Pyodide global namespace), we can bind JavaScript variables to Python objects without having direct access to that global namespace.
|
||||
|
||||
Include the following script tag anywhere in your html document:
|
||||
|
||||
```html
|
||||
<script>
|
||||
function createObject(object, variableName){
|
||||
//Bind a variable whose name is the string variableName
|
||||
// to the object called 'object'
|
||||
let execString = variableName + " = object"
|
||||
console.log("Running '" + execString + "'");
|
||||
eval(execString)
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
This function takes a Python Object and creates a variable pointing to it in the JavaScript global scope.
|
||||
|
||||
### Exporting all Global Python Objects
|
||||
|
||||
We can use our new `createObject` function to "export" the entire Python global object dictionary as a JavaScript object:
|
||||
|
||||
```python
|
||||
<py-script>
|
||||
from js import createObject
|
||||
from pyodide.ffi import create_proxy
|
||||
createObject(create_proxy(globals()), "pyodideGlobals")
|
||||
</py-script>
|
||||
```
|
||||
This will make all Python global variables available in JavaScript with `pyodideGlobals.get('my_variable_name')`.
|
||||
|
||||
(Since PyScript tags evaluate _after_ all JavaScript on the page, we can't just dump a `console.log(...)` into a `<script>` tag, since that tag will evaluate before any PyScript has a chance to. We need to delay accessing the Python variable in JavaScript until after the Python code has a chance to run. The following example uses a button with `id="do-math"` to achieve this, but any method would be valid.)
|
||||
|
||||
```python
|
||||
<py-script>
|
||||
# create some Python objects:
|
||||
symbols = {'pi': 3.1415926, 'e': 2.7182818}
|
||||
|
||||
def rough_exponential(x):
|
||||
return symbols['e']**x
|
||||
|
||||
class Circle():
|
||||
def __init__(self, radius):
|
||||
self.radius = radius
|
||||
|
||||
@property
|
||||
def area:
|
||||
return symbols['pi'] * self.radius**2
|
||||
</py-script>
|
||||
```
|
||||
|
||||
```html
|
||||
<input type="button" value="Log Python Variables" id="do-mmath">
|
||||
<script>
|
||||
document.getElementById("do-math").addEventListener("click", () => {
|
||||
const exp = pyodideGlobals.get('rough_exponential');
|
||||
console.log("e squared is about ${exp(2)}");
|
||||
const c = pyodideGlobals.get('Circle')(4);
|
||||
console.log("The area of c is ${c.area}");
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
|
||||
### Exporting Individual Python Objects
|
||||
|
||||
We can also export individual Python objects to the JavaScript global scope if we wish.
|
||||
|
||||
(As above, the following example uses a button to delay the execution of the `<script>` until after the PyScript has run.)
|
||||
|
||||
```python
|
||||
<py-script>
|
||||
import js
|
||||
from pyodide.ffi import create_proxy
|
||||
|
||||
# Create 3 python objects
|
||||
language = "Python 3"
|
||||
animals = ['dog', 'cat', 'bird']
|
||||
multiply3 = lambda a, b, c: a * b * c
|
||||
|
||||
# js object can be named the same as Python objects...
|
||||
js.createObject(language, "language")
|
||||
|
||||
# ...but don't have to be
|
||||
js.createObject(create_proxy(animals), "animals_from_py")
|
||||
|
||||
# functions are objects too, in both Python and Javascript
|
||||
js.createObject(create_proxy(multiply3), "multiply")
|
||||
</py-script>
|
||||
```
|
||||
```html
|
||||
<input type="button" value="Log Python Variables" id="log-python-variables">
|
||||
<script>
|
||||
document.getElementById("log-python-variables").addEventListener("click", () => {
|
||||
console.log(`Nice job using ${language}`);
|
||||
for (const animal of animals_from_py){
|
||||
console.log(`Do you like ${animal}s? `);
|
||||
}
|
||||
console.log(`2 times 3 times 4 is ${multiply(2,3,4)}`);
|
||||
});
|
||||
</script>
|
||||
```
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 108 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB |
@@ -1,57 +0,0 @@
|
||||
# PyScript
|
||||
|
||||
```{warning}
|
||||
Please note, this documentation is just a placeholder and **should not be used
|
||||
in reference material**. Thank you!
|
||||
```
|
||||
|
||||
Welcome to the PyScript documentation!
|
||||
|
||||
PyScript provides a way for you to run Python code directly in your browser, giving
|
||||
anyone the ability to program without infrastructure barriers. Add an interactive
|
||||
Python REPL directly to your website, share an interactive dashboard with a colleague
|
||||
as an HTML file, or create a client-side Python-powered web application. This documentation
|
||||
will show you how.
|
||||
|
||||
::::{grid} 2
|
||||
:gutter: 3
|
||||
|
||||
:::{grid-item-card} [Tutorials](tutorials/index.md)
|
||||
|
||||
Just getting started with PyScript?
|
||||
|
||||
Check out our [getting started guide](tutorials/getting-started.md)!
|
||||
:::
|
||||
:::{grid-item-card} [How-to guides](howtos/index.md)
|
||||
|
||||
You already know the basics and want to learn specifics!
|
||||
|
||||
[Passing Objects between JavaScript and Python](howtos/passing-objects.md)
|
||||
[Making async HTTP requests in pure Python](howtos/http-requests.md)
|
||||
|
||||
:::
|
||||
:::{grid-item-card} [Concepts](concepts/index.md)
|
||||
|
||||
[What is PyScript?](concepts/what-is-pyscript.md)
|
||||
|
||||
:::
|
||||
:::{grid-item-card} [Reference](reference/index.md)
|
||||
|
||||
[Frequently asked questions](reference/faq.md)
|
||||
|
||||
:::{toctree}
|
||||
:maxdepth: 1
|
||||
|
||||
:::
|
||||
::::
|
||||
|
||||
```{toctree}
|
||||
---
|
||||
maxdepth: 1
|
||||
hidden:
|
||||
---
|
||||
tutorials/index
|
||||
howtos/index
|
||||
concepts/index
|
||||
reference/index
|
||||
```
|
||||
@@ -1,35 +0,0 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.https://www.sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
||||
@@ -1,160 +0,0 @@
|
||||
# Frequently asked questions
|
||||
|
||||
As the world’s most popular programming language, Python is powerful in its capabilities and comparatively easy to learn, yet the limitations cannot be ignored: it’s hard to install Python and all necessary dependencies; it’s glued to the backend without the ability to make apps or websites; and it’s difficult to share your work.
|
||||
|
||||
What if we could remove those limitations, making the power of Python accessible to the masses? The makers of PyScript set out to do just that by enabling Python in the browser for frontend web and application development. No more complicated installs. Projects can be shared with anyone, anywhere—all you need is a browser.
|
||||
|
||||
We are fully leaning into the idea that the browser is the most ubiquitous VM by using Python to build a graphical, programmable OS on top to make and share applications. Harness the full power of canvas, webGL, WASI, and even in-browser support for P2P and CRDTs for serverless data sharing and collaboration.
|
||||
|
||||
> “This is the exciting beginning for supporting new ways of programming, building, sharing, and deploying applications. Ultimately, we should be spending our time thinking and writing applications to solve the real problems we have, not dealing with mundane, hardware-induced challenges. Let's make programming more fun and simple.” - Fabio Pliger
|
||||
|
||||
## Why PyScript?
|
||||
|
||||
Exponentially expand accessibility and use cases for Python by enabling Python in the browser for building UIs. Reproduce environments without having to download Python or conda or install other packages. Projects can be shared with anyone and deployed anywhere—all you need is a browser and a web-accessible device (computer, tablet, or mobile).
|
||||
|
||||
We are fully leaning into the idea that the browser is the most ubiquitous VM by using Python to build a graphical, programmable operating system on top of the browser to make and share applications. Harness the full power of canvas, webGL, WASI, and even in-browser support for P2P and CRDTs for serverless data sharing and collaboration.
|
||||
|
||||
- [PyCon US 2022 Keynote with Peter Wang](https://anaconda.cloud/pyscript-pycon2022-peter-wang-keynote)
|
||||
- [Example demos from Keynote](https://pyscript.net/examples/index.html)
|
||||
|
||||
## What is PyScript?
|
||||
|
||||
PyScript is a framework that allows users to create rich Python applications in the browser using HTML's interface and the power of [Pyodide — Version 0.20.0](https://pyodide.org/en/stable/), [WebAssembly](https://webassembly.org/), and modern web technologies. The PyScript framework provides users at every experience level with access to an expressive, easy-to-learn programming language with countless applications.
|
||||
|
||||
What is PyScript? Well, here are some of the core components:
|
||||
|
||||
- Python in the browser: Enable drop-in content, external file hosting, and application hosting without the reliance on server-side configuration
|
||||
|
||||
- Python ecosystem: Run many popular packages of Python and the scientific stack (such as numpy, pandas, scikit-learn, and more)
|
||||
|
||||
- Python with JavaScript: Bi-directional communication between Python and Javascript objects and namespaces
|
||||
|
||||
- Environment management: Allow users to define what packages and files to include for the page code to run
|
||||
|
||||
- Visual application development: Use readily available curated UI components, such as buttons, containers, text boxes, and more
|
||||
|
||||
- Flexible framework: A flexible framework that can be leveraged to create and share new pluggable and extensible components directly in Python
|
||||
|
||||
All that to say... PyScript is just HTML, only a bit (okay, maybe a lot) more powerful, thanks to the rich and accessible ecosystem of Python libraries.
|
||||
|
||||
In short, our mission is to enable programming for the 99%.
|
||||
|
||||
## How can a user get started?
|
||||
|
||||
Leveraging Python in HTML is literally as simple as adding a few lines of code to your page. The best place to learn more, get started, and stay updated on all things PyScript is [Pyscript.net](http://pyscript.net/). Additional shareable resources below:
|
||||
|
||||
- [PyScript Repo](https://github.com/pyscript/pyscript)
|
||||
- [PyScript Announcement Blog](https://www.anaconda.com/blog/pyscript-python-in-the-browser)
|
||||
- [PyScript Technical Blog](https://engineering.anaconda.com/2022/04/welcome-pyscript.html)
|
||||
- [PyScript Nucleus Project](https://anaconda.cloud/s/pyscript)
|
||||
- [PyScript Documentation](https://docs.pyscript.net/)
|
||||
|
||||
## Why isn't this going to be as terrible as PHP?
|
||||
|
||||
This comparison is based on both PHP and PyScript having a similar way of declaring things: put a tag on the page and the interpreter handles it. PHP works on the server side and is itself a whole different programming language that has its own directives and semantics.
|
||||
|
||||
The choice of using tags to allow people to execute Python is explicit; even if this functionality is similar to PHP, it works differently. First of all, everything runs in the browser itself rather than going to the server side. Secondly, PyScript lives close to the text and allows changes to be made to the visual elements. The PyScript REPL can generate output, plus it provides additional visual elements like buttons, titles, and input boxes. PyScript functions as a framework that generates UIs that makes sense as a tag in the html code.
|
||||
|
||||
Currently, both PHP and PyScript operate with only one namespace. However, PyScript will soon support multiple namespaces and different types of isolation of code (scope), along with support for languages beyond Python.
|
||||
|
||||
## Why not just learn JavaScript?
|
||||
|
||||
JavaScript is not only a different language from python, but a challenging language at that. With PyScript, you now have two languages to choose from, with even more on the roadmap. PyScript allows you to use both libraries and makes JavaScript and Python compatible with one another.
|
||||
|
||||
Python is incredibly powerful, super intuitive, and easy to learn. By adding Python to your toolkit, you can use Numpy, SciPy, Pandas, and more, seamlessly. One tradeoff is longer download times, so it isn’t the right tool for everything—but where it is the right tool, it’s almost irreplaceable.
|
||||
|
||||
Ultimately, PyScript will enable the use of a variety of languages, offer a standard set of components that is well linked to the REPLs, and allow you to do an introspection on the code base—you can have, for example, a *modifiable* chart as a python object.
|
||||
|
||||
## Will PyScript replace JavaScript?
|
||||
|
||||
No. PyScript allows Python to leverage HTML, CSS, and JavaScript conventions to build elegant UIs and address general web application building, packaging, distribution, and deployment challenges (a huge pain). We expect the popularity and adoption of HTML, CSS, and JavaScript to rise alongside Python, ultimately making the web a more friendly and hackable place for everyone. That said, we do believe:
|
||||
|
||||
- PyScript will displace some use cases that people have to rely on Javascript for now
|
||||
- PyScript will heavily leverage and interface with existing powerful, feature-full JS libraries, as appropriate
|
||||
- PyScript will open up web programming to tens of millions of people who would otherwise not have touched JavaScript; so in this way, it will outpace JavaScript
|
||||
|
||||
But none of these above scenarios lead to a situation where "PyScript replaces all existing JavaScript." Just as Python itself didn't replace C, C++, or Java. But, it did take a LOT of market share for new use cases where those languages would otherwise have been used.
|
||||
|
||||
## What is the difference between PyScript and Pyodide?
|
||||
|
||||

|
||||
|
||||
PyScript provides HTML tags for embedding and executing Python code in your browser. As a ‘glue’ framework, it sits on top of a variety of tools and provides users access to Pyodide, the WebAssembly port of CPython, which is compiled using Emscripten. In other words, Pyodide enables PyScript users to take advantage of real CPython on the browser.
|
||||
|
||||
Together, PyScript and Pyodide allow users to author applications by turning the browser into a code deployment tool that anyone can learn to use.
|
||||
|
||||
With respect to the UI, PyScript is opinionated and purposeful, while Pyodide is agnostic, unopinionated, and intended for more general use.
|
||||
|
||||
## What packages can I use? Can I use anything from PyPI?
|
||||
|
||||
You can use anything within the Pyodide library, and pure python packages from PyPi that do not contain C dependencies should be supported by Pyodide.
|
||||
|
||||
There is a list of packages built in Pyodide in [Packages built in Pyodide — Version 0.20.0](https://pyodide.org/en/stable/usage/packages-in-pyodide.html) (these are mostly packages with C extensions). You can also install pure Python packages from PyPI or custom URLs, assuming they have a wheel.
|
||||
|
||||
In general, Pyodide doesn’t support all Python features—not because of Pyodide itself, but because some concepts just work differently on the browser (think of sockets/websockets, IO, threading, etc.). If it’s a pure python package that doesn’t have any non-supported features, you should expect it to work. If it has C dependencies, etc., don’t expect it to work unless someone builds/ports them. A lot of the features that don’t work can be made to work, but it will take human power to fix. For example, the PyTorch community wanted those features to work, so they rallied around it to make it happen. Expect the set of libraries that work to grow quickly given the volume of package builds coming from the community.
|
||||
|
||||
## This package XXX is not supported because it has C dependencies. How can I make it work?
|
||||
|
||||
See [Creating a Pyodide package — Version 0.20.0](https://pyodide.org/en/stable/development/new-packages.html).
|
||||
|
||||
## Why is PyScript loading so slowly? Why can’t we put things behind a CDN?
|
||||
|
||||
Packages are already served from the JsDelivr CDN. This is not a downloading speed problem—it's WASM assembly time. PyScript loads slowly because the Python standard library and packages are large and WebAssembly code needs to be compiled and run by the browser after they are loaded for the first time.
|
||||
|
||||
Currently, there are efforts to mitigate the problem, and Pyodide is currently working on a bundler, for instance.
|
||||
|
||||
## Is PyScript owned by Anaconda?
|
||||
|
||||
Anaconda doesn’t own PyScript. It is an open source project developed by Anaconda internally, and Anaconda team members are currently the main contributors, but the repo itself is public. We are working on a steering council to ensure the project stays public and owned by the community.
|
||||
|
||||
See [Maintainers](../concepts/governance/maintainers.md).
|
||||
|
||||
See [Governance Policy](../concepts/governance/policy.md).
|
||||
|
||||
## What is the governing model for PyScript?
|
||||
|
||||
See [Governance Policy](../concepts/governance/policy.md).
|
||||
|
||||
## What is the license?
|
||||
|
||||
PyScript uses the Apache-2.0 license.
|
||||
|
||||
Pyodide uses MPL-2.0 license. Various packages are distributed under their corresponding license.
|
||||
|
||||
## Is Pyodide a replacement for CPython? How does PyScript and Pyodide compare to CPython on WASM?
|
||||
|
||||
No. They have different elements that do different things, both of which are additive.
|
||||
|
||||
PyScript sits on top of everything. Pyodide came before the work on CPython and WASM. Patches were created in order for it to work, but now that CPython/WASM are progressing, Pyodide is able to remove a few of those patches. Additionally, CPython doesn’t deal with building Python packages for WASM. WASM related work on upstream CPython will integrate into Pyodide in the near future.
|
||||
|
||||
For a list of differences from “standard” CPython, see [Pyodide Python compatibility — Version 0.20.0](https://pyodide.org/en/stable/usage/wasm-constraints.html).
|
||||
|
||||
## Hasn’t this already been done before by Brython/skulpt?
|
||||
|
||||
No. Brython and Skulpt accomplish different things than PyScript and Pyodide.
|
||||
|
||||
Brython is client-side and functions as syntax on top of Javascript—it is a reimplementation of Python on top of Javascript, without support for packages or a file system. The extraction of a package in normal Python has been replaced completely by something else. You should be able to run code with minimal changes; however, that isn’t possible with Brython.
|
||||
|
||||
Skulpt is a cross compiler from Python to Javascript, leveraged for compatibility with the Python ecosystem. If you want to do any more Python, you would have to send it over.
|
||||
|
||||
Fairly similar syntax to normal Python, but not exactly the same. If Brython was an interpreter and a full Python implementation, it could be used with PyScript to leverage packages like Numpy, but that isn’t possible as it stands today. They do have the Python script tag, but it is a smaller API and not as feature rich—which is why PyScript is built on Pyodide, Emscripten, and WebAssembly.
|
||||
|
||||
## How can I contribute/help?
|
||||
|
||||
**PyScript** - we are currently working on building documentation and a contributing guide. In the meantime, just ask to help on the PyScript [discussions page](https://anaconda.cloud/s/pyscript) or in the [repo](http://github.com/pyscript/pyscript).
|
||||
|
||||
**Pyodide** - refer to [Pyodide docs](https://pyodide.org/en/stable/development/contributing.html).
|
||||
|
||||
## WebAssembly Security
|
||||
|
||||
See [WebAssembly docs](https://webassembly.org/docs/security/).
|
||||
|
||||
## Why don’t Requests and Black work?
|
||||
|
||||
Requests and Black do not work out of the box because they weren’t meant for the browser. On the browser, sockets multiprocessing works differently, so there is work to be done to actually match things.
|
||||
|
||||
For Black, it’s a design choice that can be patched. This is currently being addressed by the team at Pyodide.
|
||||
|
||||
Requests do not work because of the sockets issue (sockets and websockets are two different things) and requests are blocking—which you don’t want in the browser. It’ll require putting the runtime on a webworker and utilizing an assistant, but on the main thread it’s unlikely that it’ll work.
|
||||
|
||||
There are options as a path forward. For example, Requests can be leveraged using javascript libraries, or building a python async version of Requests API or a python wrapper for fetch (pyfetch), etc. The websockets library has a client side that could be made to work—given that it has all asynchronous APIs, there’s nothing fundamentally difficult about getting it to work.
|
||||
@@ -1,11 +0,0 @@
|
||||
# Reference
|
||||
|
||||
This reference section will have manually documented or fully
|
||||
automated code documentation. **Coming soon!**
|
||||
|
||||
```{toctree}
|
||||
---
|
||||
maxdepth: 1
|
||||
glob:
|
||||
---
|
||||
faq
|
||||
@@ -1,5 +0,0 @@
|
||||
User-agent: *
|
||||
Disallow: /review/
|
||||
|
||||
Sitemap: https://docs.pyscript.net/sitemap.xml
|
||||
Host: docs.pyscript.net
|
||||
@@ -1,3 +0,0 @@
|
||||
# Deployment
|
||||
|
||||
**Coming soon!**
|
||||
@@ -1,504 +0,0 @@
|
||||
# Getting started with PyScript
|
||||
|
||||
This page will guide you through getting started with PyScript.
|
||||
|
||||
## Development setup
|
||||
|
||||
PyScript does not require any development environment other
|
||||
than a web browser (we recommend using [Chrome](https://www.google.com/chrome/)) and a text editor, even though using your [IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) of choice might be convenient.
|
||||
|
||||
If you're using [VSCode](https://code.visualstudio.com/), the
|
||||
[Live Server extension](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer)
|
||||
can be used to reload the page as you edit the HTML file.
|
||||
|
||||
## Trying before installing
|
||||
|
||||
If you're new to programming and know nothing about HTML or just want to try some of PyScript features, we recommend using the [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) element in the [PyScript REPL example](https://pyscript.net/examples/repl.html) instead so you can have a programming experience in a REPL that doesn't require any setup. This REPL can be used to have an interactive experience using Python directly.
|
||||
|
||||
Alternatively, you can also use an online editor like W3School's [TryIt Editor](https://www.w3schools.com/html/tryit.asp?filename=tryhtml_default_default) and just plug the code below into it, as shown in the [example](https://docs.pyscript.net/latest/concepts/what-is-pyscript.html#example) page and click the run button.
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
|
||||
<title>REPL</title>
|
||||
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
Hello world! <br>
|
||||
This is the current date and time, as computed by Python:
|
||||
<py-script>
|
||||
from datetime import datetime
|
||||
now = datetime.now()
|
||||
now.strftime("%m/%d/%Y, %H:%M:%S")
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
You could try changing the code above to explore and play with pyscript yourself.
|
||||
|
||||
## Installation
|
||||
|
||||
There is no installation required. In this document, we'll use
|
||||
the PyScript assets served on [https://pyscript.net](https://pyscript.net).
|
||||
|
||||
If you want to download the source and build it yourself, follow
|
||||
the instructions in the [README.md](https://github.com/pyscript/pyscript/blob/main/README.md) file.
|
||||
|
||||
## Your first PyScript HTML file
|
||||
|
||||
Here's a "Hello, world!" example using PyScript.
|
||||
|
||||
Using your favorite editor, create a new file called `hello.html` in
|
||||
the same directory as your PyScript, JavaScript, and CSS files with the
|
||||
following content, and open the file in your web browser. You can typically
|
||||
open an HTML by double-clicking it in your file explorer.
|
||||
|
||||
```html
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
<body> <py-script> print('Hello, World!') </py-script> </body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Notice the use of the `<py-script>` tag in the HTML body. This
|
||||
is where you'll write your Python code. In the following sections, we'll
|
||||
introduce the eight tags provided by PyScript.
|
||||
|
||||
## The py-script tag
|
||||
|
||||
The `<py-script>` tag lets you execute multi-line Python scripts and
|
||||
print back onto the page. For example, we can compute π.
|
||||
|
||||
```html
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<py-script>
|
||||
print("Let's compute π:")
|
||||
def compute_pi(n):
|
||||
pi = 2
|
||||
for i in range(1,n):
|
||||
pi *= 4 * i ** 2 / (4 * i ** 2 - 1)
|
||||
return pi
|
||||
|
||||
pi = compute_pi(100000)
|
||||
s = f"π is approximately {pi:.3f}"
|
||||
print(s)
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### Writing into labeled elements
|
||||
|
||||
In the example above, we had a single `<py-script>` tag printing
|
||||
one or more lines onto the page in order. Within the `<py-script>`, you
|
||||
have access to the `pyscript` module, which provides a `.write()` method
|
||||
to send strings into labeled elements on the page.
|
||||
|
||||
For example, we'll add some style elements and provide placeholders for
|
||||
the `<py-script>` tag to write to.
|
||||
|
||||
```html
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<b><p>Today is <u><label id='today'></label></u></p></b>
|
||||
<br>
|
||||
<div id="pi" class="alert alert-primary"></div>
|
||||
<py-script>
|
||||
import datetime as dt
|
||||
pyscript.write('today', dt.date.today().strftime('%A %B %d, %Y'))
|
||||
|
||||
def compute_pi(n):
|
||||
pi = 2
|
||||
for i in range(1,n):
|
||||
pi *= 4 * i ** 2 / (4 * i ** 2 - 1)
|
||||
return pi
|
||||
|
||||
pi = compute_pi(100000)
|
||||
pyscript.write('pi', f'π is approximately {pi:.3f}')
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## The py-config tag
|
||||
|
||||
Use the `<py-config>` tag to set and configure general metadata along with declaring dependencies for your PyScript application. The configuration has to be set in either TOML or JSON format. If you are unfamiliar with JSON, consider reading [freecodecamp's JSON for beginners](https://www.freecodecamp.org/news/what-is-json-a-json-file-example/) guide for more information. And for TOML, consider reading about it [here](https://learnxinyminutes.com/docs/toml/).
|
||||
|
||||
The ideal place to use `<py-config>` in between the `<head>...</head>` tags.
|
||||
|
||||
The `<py-config>` tag can be used as follows:
|
||||
|
||||
```html
|
||||
<py-config>
|
||||
autoclose_loader = true
|
||||
|
||||
[[runtimes]]
|
||||
src = "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js"
|
||||
name = "pyodide-0.21.2"
|
||||
lang = "python"
|
||||
</py-config>
|
||||
```
|
||||
|
||||
Alternatively, a JSON config can be passed using the `type` attribute.
|
||||
|
||||
```html
|
||||
<py-config type="json">
|
||||
{
|
||||
"autoclose_loader": true,
|
||||
"runtimes": [{
|
||||
"src": "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js",
|
||||
"name": "pyodide-0.21.2",
|
||||
"lang": "python"
|
||||
}]
|
||||
}
|
||||
</py-config>
|
||||
```
|
||||
|
||||
Besides passing the config as inline (as shown above), one can also pass it with the `src` attribute. This is demonstrated below:
|
||||
|
||||
```
|
||||
<py-config src="./custom.toml"></py-config>
|
||||
```
|
||||
|
||||
where `custom.toml` contains
|
||||
|
||||
```
|
||||
autoclose_loader = true
|
||||
[[runtimes]]
|
||||
src = "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js"
|
||||
name = "pyodide-0.21.2"
|
||||
lang = "python"
|
||||
```
|
||||
|
||||
This can also be done via JSON using the `type` attribute. By default, `type` is set to `"toml"` if not supplied.
|
||||
|
||||
```
|
||||
<py-config type="json" src="./custom.json"></py-config>
|
||||
```
|
||||
|
||||
where `custom.json` contains
|
||||
|
||||
```
|
||||
{
|
||||
"autoclose_loader": true,
|
||||
"runtimes": [{
|
||||
"src": "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js",
|
||||
"name": "pyodide-0.21.2",
|
||||
"lang": "python"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
One can also use both i.e pass the config from `src` attribute as well as specify it as `inline`. So the following snippet is also valid:
|
||||
|
||||
```
|
||||
<py-config src="./custom.toml">
|
||||
paths = ["./utils.py"]
|
||||
</py-config>
|
||||
```
|
||||
|
||||
This can also be done via JSON using the `type` attribute.
|
||||
|
||||
```
|
||||
<py-config type="json" src="./custom.json">
|
||||
{
|
||||
"paths": ["./utils.py"]
|
||||
}
|
||||
</py-config>
|
||||
```
|
||||
|
||||
Note: While the `<py-config>` tag supports both TOML and JSON, one cannot mix the type of config passed from 2 different sources i.e. the case when inline config is in TOML format while config from src is in JSON format is NOT allowed. Similarly for the opposite case.
|
||||
|
||||
---
|
||||
|
||||
This is helpful in cases where a number of applications share a common configuration (which can be supplied via `src`), but their specific keys need to be customised and overridden.
|
||||
|
||||
The keys supplied through `inline` override the values present in config supplied via `src`.
|
||||
|
||||
One can also declare dependencies so as to get access to many 3rd party OSS packages that are supported by PyScript.
|
||||
You can also link to `.whl` files directly on disk like in our [toga example](https://github.com/pyscript/pyscript/blob/main/examples/toga/freedom.html).
|
||||
|
||||
```
|
||||
<py-config>
|
||||
packages = ["./static/wheels/travertino-0.1.3-py3-none-any.whl"]
|
||||
</py-config>
|
||||
```
|
||||
|
||||
OR in JSON like
|
||||
|
||||
```
|
||||
<py-config type="json">
|
||||
{
|
||||
"packages": ["./static/wheels/travertino-0.1.3-py3-none-any.whl"]
|
||||
}
|
||||
</py-config>
|
||||
```
|
||||
|
||||
If your `.whl` is not a pure Python wheel, then open a PR or issue with [pyodide](https://github.com/pyodide/pyodide) to get it added [here](https://github.com/pyodide/pyodide/tree/main/packages).
|
||||
If there's enough popular demand, the pyodide team will likely work on supporting your package. Regardless, things will likely move faster if you make the PR and consult with the team to get unblocked.
|
||||
For example, NumPy and Matplotlib are available. Notice here we're using `<py-script output="plot">`
|
||||
as a shortcut, which takes the expression on the last line of the script and runs `pyscript.write('plot', fig)`.
|
||||
```html
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<py-config type="json">
|
||||
{
|
||||
"packages": ["numpy", "matplotlib"]
|
||||
}
|
||||
</py-config>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Let's plot random numbers</h1>
|
||||
<div id="plot"></div>
|
||||
<py-script output="plot">
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
x = np.random.randn(1000)
|
||||
y = np.random.randn(1000)
|
||||
fig, ax = plt.subplots()
|
||||
ax.scatter(x, y)
|
||||
fig
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### Local modules
|
||||
In addition to packages, you can declare local Python modules that will
|
||||
be imported in the `<py-script>` tag. For example, we can place the random
|
||||
number generation steps in a function in the file `data.py`.
|
||||
```python
|
||||
# data.py
|
||||
import numpy as np
|
||||
def make_x_and_y(n):
|
||||
x = np.random.randn(n)
|
||||
y = np.random.randn(n)
|
||||
return x, y
|
||||
```
|
||||
|
||||
In the HTML tag `<py-config>`, paths to local modules are provided in the
|
||||
`paths:` key.
|
||||
|
||||
```html
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<py-config type="toml">
|
||||
packages = ["numpy", "matplotlib"]
|
||||
paths = ["./data.py"]
|
||||
</py-config>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Let's plot random numbers</h1>
|
||||
<div id="plot"></div>
|
||||
<py-script output="plot">
|
||||
import matplotlib.pyplot as plt
|
||||
from data import make_x_and_y
|
||||
x, y = make_x_and_y(n=1000)
|
||||
fig, ax = plt.subplots()
|
||||
ax.scatter(x, y)
|
||||
fig
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
The following optional values are supported by `<py-config>`:
|
||||
| Value | Type | Description |
|
||||
| ------ | ---- | ----------- |
|
||||
| `name` | string | Name of the user application. This field can be any string and is to be used by the application author for their own customization purposes. |
|
||||
| `description` | string | Description of the user application. This field can be any string and is to be used by the application author for their own customization purposes. |
|
||||
| `version` | string | Version of the user application. This field can be any string and is to be used by the application author for their own customization purposes. It is not related to the PyScript version. |
|
||||
| `schema_version` | number | The version of the config schema which determines what all keys are supported. This can be supplied by the user so PyScript knows what to expect in the config. If not supplied, the latest version for the schema is automatically used. |
|
||||
| `type` | string | Type of the project. The default is an "app" i.e. a user application |
|
||||
| `author_name` | string | Name of the author. |
|
||||
| `author_email` | string | Email of the author. |
|
||||
| `license` | string | License to be used for the user application. |
|
||||
| `autoclose_loader` | boolean | If false, PyScript will not close the loading splash screen when the startup operations finish. |
|
||||
| `packages` | List of Packages | Dependencies on 3rd party OSS packages are specified here. The default value is an empty list. |
|
||||
| `paths` | List of Paths | Local Python modules are to be specified here. The default value is an empty list. |
|
||||
| `plugins` | List of Plugins | List of Plugins are to be specified here. The default value is an empty list. |
|
||||
| `runtimes` | List of Runtimes | List of runtime configurations, described below. The default value contains a single Pyodide based runtime. |
|
||||
|
||||
A runtime configuration consists of the following:
|
||||
| Value | Type | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| `src` | string (Required) | URL to the runtime source. |
|
||||
| `name` | string | Name of the runtime. This field can be any string and is to be used by the application author for their own customization purposes |
|
||||
| `lang` | string | Programming language supported by the runtime. This field can be used by the application author to provide clarification. It currently has no implications on how PyScript behaves. |
|
||||
|
||||
Besides the above format, a user can also supply any extra keys and values that are relevant as metadata information or perhaps are being used within the application.
|
||||
|
||||
For example, a valid config could also be with the snippet below:
|
||||
|
||||
```
|
||||
<py-config type="toml">
|
||||
magic = "unicorn"
|
||||
</py-config>
|
||||
```
|
||||
|
||||
OR in JSON like
|
||||
|
||||
```
|
||||
<py-config type="json">
|
||||
{
|
||||
"magic": "unicorn"
|
||||
}
|
||||
</py-config>
|
||||
```
|
||||
|
||||
If this `"magic"` key is present in config supplied via `src` and also present in config supplied via `inline`, then the value in the inline config is given priority i.e. the overriding process also works for custom keys.
|
||||
|
||||
## The py-env tag (Deprecated)
|
||||
|
||||
**The <py-env> tag is deprecated as of `2022.09.1` release but you can still use the functionality explained below. It will be removed in the next release. To specify packages in the recommended way, please see the <py-config> section.**
|
||||
|
||||
In addition to the [Python Standard Library](https://docs.python.org/3/library/) and
|
||||
the `pyscript` module, many 3rd-party OSS packages will work out-of-the-box with PyScript.
|
||||
|
||||
In order to use them, you will need to declare the dependencies using the `<py-env>` tag in the
|
||||
HTML head. You can also link to `.whl` files directly on disk like in our [toga example](https://github.com/pyscript/pyscript/blob/main/examples/toga/freedom.html).
|
||||
|
||||
```
|
||||
<py-env>
|
||||
- './static/wheels/travertino-0.1.3-py3-none-any.whl'
|
||||
</py-env>
|
||||
```
|
||||
|
||||
If your `.whl` is not a pure Python wheel, then open a PR or issue with [pyodide](https://github.com/pyodide/pyodide) to get it added [here](https://github.com/pyodide/pyodide/tree/main/packages).
|
||||
If there's enough popular demand, the pyodide team will likely work on supporting your package. Regardless, things will likely move faster if you make the PR and consult with the team to get unblocked.
|
||||
|
||||
For example, NumPy and Matplotlib are available. Notice here we're using `<py-script output="plot">`
|
||||
as a shortcut, which takes the expression on the last line of the script and runs `pyscript.write('plot', fig)`.
|
||||
|
||||
```html
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<py-env>
|
||||
- numpy
|
||||
- matplotlib
|
||||
</py-env>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Let's plot random numbers</h1>
|
||||
<div id="plot"></div>
|
||||
<py-script output="plot">
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
x = np.random.randn(1000)
|
||||
y = np.random.randn(1000)
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
ax.scatter(x, y)
|
||||
fig
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### Local modules with py-env (Deprecated)
|
||||
|
||||
**The <py-env> tag is deprecated as of `2022.09.1` release but you can still use the functionality explained below. It will be removed in the next release. To specify local modules in the recommended way, please see the <py-config> section.**
|
||||
|
||||
In addition to packages, you can declare local Python modules that will
|
||||
be imported in the `<py-script>` tag. For example, we can place the random
|
||||
number generation steps in a function in the file `data.py`.
|
||||
```python
|
||||
# data.py
|
||||
import numpy as np
|
||||
def make_x_and_y(n):
|
||||
x = np.random.randn(n)
|
||||
y = np.random.randn(n)
|
||||
return x, y
|
||||
```
|
||||
|
||||
In the HTML tag `<py-env>`, paths to local modules are provided in the
|
||||
`paths:` key.
|
||||
|
||||
```html
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<py-env>
|
||||
- numpy
|
||||
- matplotlib
|
||||
- paths:
|
||||
- ./data.py
|
||||
</py-env>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Let's plot random numbers</h1>
|
||||
<div id="plot"></div>
|
||||
<py-script output="plot">
|
||||
import matplotlib.pyplot as plt
|
||||
from data import make_x_and_y
|
||||
x, y = make_x_and_y(n=1000)
|
||||
fig, ax = plt.subplots()
|
||||
ax.scatter(x, y)
|
||||
fig
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## The py-repl tag
|
||||
|
||||
The `<py-repl>` tag creates a REPL component that is rendered to the page as a code editor, allowing you to write executable code inline.
|
||||
```html
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
<py-repl></py-repl>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Visual component tags
|
||||
|
||||
The following tags can be used to add visual attributes to your HTML page.
|
||||
|
||||
| Tag | Description |
|
||||
| --- | ----------- |
|
||||
| `<py-inputbox>` | Adds an input box that can be used to prompt users to enter input values. |
|
||||
| `<py-box>` | Creates a container object that can be used to host one or more visual components that define how elements of `<py-box>` should align and show on the page. |
|
||||
| `<py-button>` | Adds a button to which authors can add labels and event handlers for actions on the button, such as `on_focus` or `on_click`. |
|
||||
| `<py-title>` | Adds a static text title component that styles the text inside the tag as a page title. |
|
||||
|
||||
```{note}
|
||||
All the elements above are experimental and not implemented at their full functionality. Use them with the understanding that the APIs or full support might change or be removed until the visual components are more mature.
|
||||
```
|
||||
@@ -1,12 +0,0 @@
|
||||
# Tutorials
|
||||
|
||||
This is the tutorials section for beginners.
|
||||
|
||||
```{toctree}
|
||||
---
|
||||
maxdepth: 2
|
||||
---
|
||||
getting-started
|
||||
deployment
|
||||
setup
|
||||
```
|
||||
@@ -1,3 +0,0 @@
|
||||
# Setup
|
||||
|
||||
**Coming soon!**
|
||||
@@ -1,62 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Altair</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<py-config>
|
||||
packages = [
|
||||
"altair",
|
||||
"pandas",
|
||||
"vega_datasets"
|
||||
]
|
||||
</py-config>
|
||||
</head>
|
||||
<body>
|
||||
<div id="altair" style="width: 100%; height: 100%"></div>
|
||||
<py-script output="altair">
|
||||
import altair as alt
|
||||
from vega_datasets import data
|
||||
|
||||
source = data.movies.url
|
||||
|
||||
pts = alt.selection(type="single", encodings=['x'])
|
||||
|
||||
rect = alt.Chart(data.movies.url).mark_rect().encode(
|
||||
alt.X('IMDB_Rating:Q', bin=True),
|
||||
alt.Y('Rotten_Tomatoes_Rating:Q', bin=True),
|
||||
alt.Color('count()',
|
||||
scale=alt.Scale(scheme='greenblue'),
|
||||
legend=alt.Legend(title='Total Records')
|
||||
)
|
||||
)
|
||||
|
||||
circ = rect.mark_point().encode(
|
||||
alt.ColorValue('grey'),
|
||||
alt.Size('count()',
|
||||
legend=alt.Legend(title='Records in Selection')
|
||||
)
|
||||
).transform_filter(
|
||||
pts
|
||||
)
|
||||
|
||||
bar = alt.Chart(source).mark_bar().encode(
|
||||
x='Major_Genre:N',
|
||||
y='count()',
|
||||
color=alt.condition(pts, alt.ColorValue("steelblue"), alt.ColorValue("grey"))
|
||||
).properties(
|
||||
width=550,
|
||||
height=200
|
||||
).add_selection(pts)
|
||||
|
||||
alt.vconcat(
|
||||
rect + circ,
|
||||
bar
|
||||
).resolve_legend(
|
||||
color="independent",
|
||||
size="independent"
|
||||
)
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,21 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Antigravity</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
<py-config>
|
||||
paths = [
|
||||
"./antigravity.py"
|
||||
]
|
||||
</py-config>
|
||||
<body>
|
||||
<b>Based on xkcd: antigravity https://xkcd.com/353/.</b>
|
||||
<py-script>
|
||||
import antigravity
|
||||
antigravity.fly()
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,45 +0,0 @@
|
||||
import random
|
||||
import sys
|
||||
|
||||
from js import DOMParser, document, setInterval
|
||||
from pyodide.ffi import create_proxy
|
||||
from pyodide.http import open_url
|
||||
|
||||
|
||||
class Antigravity:
|
||||
|
||||
url = "./antigravity.svg"
|
||||
|
||||
def __init__(self, target=None, interval=10, append=True, fly=False):
|
||||
target = target or sys.stdout._out
|
||||
self.target = (
|
||||
document.getElementById(target) if isinstance(target, str) else target
|
||||
)
|
||||
doc = DOMParser.new().parseFromString(
|
||||
open_url(self.url).read(), "image/svg+xml"
|
||||
)
|
||||
self.node = doc.documentElement
|
||||
if append:
|
||||
self.target.append(self.node)
|
||||
else:
|
||||
self.target.replaceChildren(self.node)
|
||||
self.xoffset, self.yoffset = 0, 0
|
||||
self.interval = interval
|
||||
if fly:
|
||||
self.fly()
|
||||
|
||||
def fly(self):
|
||||
setInterval(create_proxy(self.move), self.interval)
|
||||
|
||||
def move(self):
|
||||
char = self.node.getElementsByTagName("g")[1]
|
||||
char.setAttribute("transform", f"translate({self.xoffset}, {-self.yoffset})")
|
||||
self.xoffset += random.normalvariate(0, 1) / 20
|
||||
if self.yoffset < 50:
|
||||
self.yoffset += 0.1
|
||||
else:
|
||||
self.yoffset += random.normalvariate(0, 1) / 20
|
||||
|
||||
|
||||
_auto = Antigravity(append=True)
|
||||
fly = _auto.fly
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 212 KiB |
@@ -1,51 +0,0 @@
|
||||
.example {
|
||||
margin-bottom: 5rem;
|
||||
}
|
||||
|
||||
.example h2{
|
||||
color: #000000;
|
||||
font-family: "Inconsolata", monospace;
|
||||
font-size: 2.25rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
height: 15rem;
|
||||
background-color: #FFFFFF;
|
||||
padding: 1rem;
|
||||
-webkit-box-shadow: var(--card-shadow);
|
||||
box-shadow: var(--card-shadow);
|
||||
}
|
||||
|
||||
.card a h2 {
|
||||
color: var(--color-primary);
|
||||
margin: 0;
|
||||
font-family: "Inconsolata", monospace;
|
||||
font-size: 2.25rem;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.container-card {
|
||||
max-width: 1500px;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.container-card {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 900px) {
|
||||
.container-card {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
@import url("https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;700&display=swap");
|
||||
@import "./variables.css";
|
||||
@import "./reset.css";
|
||||
|
||||
.container {
|
||||
max-width: 1510px;
|
||||
margin: auto;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
.title-main {
|
||||
color: #000000;
|
||||
font-size: 4.25rem;
|
||||
font-family: "Inconsolata", monospace;
|
||||
text-align: center;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
*,
|
||||
*:after,
|
||||
*:before {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 100%;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: "Inconsolata", monospace;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
:root {
|
||||
--color-primary: #2563eb;
|
||||
--card-shadow: 0px 5px 11px 0px rgb(0 0 0 / 15%);
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
for i in range(3):
|
||||
js.console.log('A', i)
|
||||
await asyncio.sleep(0.1)
|
||||
</py-script>
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
for i in range(3):
|
||||
js.console.log('B', i)
|
||||
await asyncio.sleep(0.1)
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,40 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
Pyscript - FIRST ASYNC WITH INVOKED LOOP BLOCKING AWAIT AT SAME LEVEL AS LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
|
||||
async def asyncCallLoop1():
|
||||
for i in range(3):
|
||||
js.console.log('A', i)
|
||||
await asyncio.sleep(2)
|
||||
|
||||
asyncCallLoop1()
|
||||
</py-script>
|
||||
</div>
|
||||
<div>
|
||||
Pyscript - SECOND ASYNC WITH INVOKED LOOP BLOCKING AWAIT AT SAME LEVEL AS LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
|
||||
async def asyncCallLoop2():
|
||||
for i in range(3):
|
||||
js.console.log('B', i)
|
||||
await asyncio.sleep(2)
|
||||
|
||||
asyncCallLoop2()
|
||||
</py-script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,37 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
Pyscript - FIRST ASYNC WITH INVOKED LOOP BLOCKING AWAIT AT SAME LEVEL AS LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
|
||||
async def asyncCallLoop1():
|
||||
for i in range(3):
|
||||
js.console.log('A', i)
|
||||
await asyncio.sleep(2)
|
||||
|
||||
asyncCallLoop1()
|
||||
</py-script>
|
||||
</div>
|
||||
<div>
|
||||
Pyscript - SECOND ASYNC WITH TOP-LEVEL LOOP BLOCKING AWAIT AT SAME LEVEL AS LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
|
||||
for i in range(3):
|
||||
js.console.log('B', i)
|
||||
await asyncio.sleep(2)
|
||||
</py-script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,40 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Async Await NON-BLOCKING Pyscript Twice</title>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
Pyscript - FIRST ASYNC WITH NON-BLOCKING AWAIT AT ONE LEVEL LOWER THAN LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
|
||||
async def asyncCall1():
|
||||
await asyncio.sleep(2)
|
||||
|
||||
for i in range(3):
|
||||
js.console.log('A', i)
|
||||
asyncCall1()
|
||||
</py-script>
|
||||
</div>
|
||||
<div>
|
||||
Pyscript - SECOND ASYNC WITH NON-BLOCKING AWAIT AT ONE LEVEL LOWER THAN LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
|
||||
async def asyncCall2():
|
||||
await asyncio.sleep(2)
|
||||
|
||||
for i in range(3):
|
||||
js.console.log('B', i)
|
||||
asyncCall2()
|
||||
</py-script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,34 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
Pyscript - FIRST ASYNC WITH TOP-LEVEL LOOP BLOCKING AWAIT AT SAME LEVEL AS LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
|
||||
for i in range(3):
|
||||
js.console.log('A', i)
|
||||
await asyncio.sleep(2)
|
||||
</py-script>
|
||||
</div>
|
||||
<div>
|
||||
Pyscript - SECOND ASYNC WITH TOP-LEVEL LOOP BLOCKING AWAIT AT SAME LEVEL AS LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
|
||||
for i in range(3):
|
||||
js.console.log('B', i)
|
||||
await asyncio.sleep(2)
|
||||
</py-script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,19 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<py-script>
|
||||
import asyncio
|
||||
from itertools import count
|
||||
for i in count():
|
||||
print(f"Count: {i}")
|
||||
await asyncio.sleep(1)
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,50 +0,0 @@
|
||||
<html><head>
|
||||
<title>Bokeh Example</title>
|
||||
<meta charset="iso-8859-1">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-gl-2.4.2.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.2.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.2.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-2.4.2.min.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<py-config>
|
||||
packages = [
|
||||
"bokeh",
|
||||
"numpy"
|
||||
]
|
||||
</py-config>
|
||||
<h1>Bokeh Example</h1>
|
||||
<div id="myplot"></div>
|
||||
|
||||
<py-script id="main">
|
||||
import json
|
||||
import pyodide
|
||||
|
||||
from js import Bokeh, console, JSON
|
||||
|
||||
from bokeh.embed import json_item
|
||||
from bokeh.plotting import figure
|
||||
from bokeh.resources import CDN
|
||||
|
||||
# create a new plot with default tools, using figure
|
||||
p = figure(plot_width=400, plot_height=400)
|
||||
|
||||
# add a circle renderer with x and y coordinates, size, color, and alpha
|
||||
p.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=15, line_color="navy", fill_color="orange", fill_alpha=0.5)
|
||||
p_json = json.dumps(json_item(p, "myplot"))
|
||||
|
||||
Bokeh.embed.embed_item(JSON.parse(p_json))
|
||||
</py-script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,100 +0,0 @@
|
||||
<html><head>
|
||||
<title>Bokeh Example</title>
|
||||
<meta charset="iso-8859-1">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-gl-2.4.2.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.2.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.2.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-2.4.2.min.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<py-config>
|
||||
packages = [
|
||||
"bokeh",
|
||||
"numpy"
|
||||
]
|
||||
</py-config>
|
||||
<h1>Bokeh Example</h1>
|
||||
<div id="myplot"></div>
|
||||
|
||||
<py-script id="main">
|
||||
import asyncio
|
||||
import json
|
||||
import pyodide
|
||||
|
||||
from js import Bokeh, console, JSON
|
||||
|
||||
from bokeh import __version__
|
||||
from bokeh.document import Document
|
||||
from bokeh.embed.util import OutputDocumentFor, standalone_docs_json_and_render_items
|
||||
from bokeh.models import Slider, Div
|
||||
from bokeh.layouts import Row
|
||||
from bokeh.protocol.messages.patch_doc import process_document_events
|
||||
|
||||
# create a new plot with default tools, using figure
|
||||
p = Slider(start=0.1, end=10, value=1, step=.1, title="Amplitude")
|
||||
div = Div(text=f'Amplitude is: {p.value}')
|
||||
|
||||
def callback(attr, old, new):
|
||||
div.text = f'Amplitude is: {new}'
|
||||
|
||||
p.on_change('value', callback)
|
||||
|
||||
row = Row(children=[p, div])
|
||||
|
||||
def doc_json(model, target):
|
||||
with OutputDocumentFor([model]) as doc:
|
||||
doc.title = ""
|
||||
docs_json, _ = standalone_docs_json_and_render_items(
|
||||
[model], suppress_callback_warning=True
|
||||
)
|
||||
|
||||
doc_json = list(docs_json.values())[0]
|
||||
root_id = doc_json['roots']['root_ids'][0]
|
||||
|
||||
return doc, json.dumps(dict(
|
||||
target_id = target,
|
||||
root_id = root_id,
|
||||
doc = doc_json,
|
||||
version = __version__,
|
||||
))
|
||||
|
||||
def _link_docs(pydoc, jsdoc):
|
||||
def jssync(event):
|
||||
if getattr(event, 'setter_id', None) is not None:
|
||||
return
|
||||
events = [event]
|
||||
json_patch = jsdoc.create_json_patch_string(pyodide.ffi.to_js(events))
|
||||
pydoc.apply_json_patch(json.loads(json_patch))
|
||||
|
||||
jsdoc.on_change(pyodide.ffi.create_proxy(jssync), pyodide.ffi.to_js(False))
|
||||
|
||||
def pysync(event):
|
||||
json_patch, buffers = process_document_events([event], use_buffers=True)
|
||||
buffer_map = {}
|
||||
for (ref, buffer) in buffers:
|
||||
buffer_map[ref['id']] = buffer
|
||||
jsdoc.apply_json_patch(JSON.parse(json_patch), pyodide.ffi.to_js(buffer_map), setter_id='js')
|
||||
|
||||
pydoc.on_change(pysync)
|
||||
|
||||
async def show(plot, target):
|
||||
pydoc, model_json = doc_json(plot, target)
|
||||
views = await Bokeh.embed.embed_item(JSON.parse(model_json))
|
||||
jsdoc = views[0].model.document
|
||||
_link_docs(pydoc, jsdoc)
|
||||
|
||||
await show(row, 'myplot')
|
||||
</py-script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
170
examples/d3.html
170
examples/d3.html
@@ -1,170 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>d3: JavaScript & PyScript visualizations side-by-side</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
|
||||
<style>
|
||||
.loading {
|
||||
display: inline-block;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 3px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
border-top-color: black;
|
||||
animation: spin 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<b>
|
||||
Based on <i><a href="https://observablehq.com/@d3/learn-d3-shapes?collection=@d3/learn-d3>">Learn D3: Shapes</a></i> tutorial.
|
||||
</b>
|
||||
<div style="display: flex; flex-direction: row">
|
||||
<div>
|
||||
<div style="text-align: center">JavaScript version</div>
|
||||
<div id="js" style="width: 400px; height: 400px">
|
||||
<div class="loading"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="text-align: center">PyScript version</div>
|
||||
<div id="py" style="width: 400px; height: 400px">
|
||||
<div class="loading"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"d3": "https://cdn.skypack.dev/pin/d3@v7.6.1-1Q0NZ0WZnbYeSjDusJT3/mode=imports,min/optimized/d3.js"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script type="module">
|
||||
import * as d3 from "https://cdn.skypack.dev/pin/d3@v7.6.1-1Q0NZ0WZnbYeSjDusJT3/mode=imports,min/optimized/d3.js";
|
||||
|
||||
const fruits = [
|
||||
{name: "🍊", count: 21},
|
||||
{name: "🍇", count: 13},
|
||||
{name: "🍏", count: 8},
|
||||
{name: "🍌", count: 5},
|
||||
{name: "🍐", count: 3},
|
||||
{name: "🍋", count: 2},
|
||||
{name: "🍎", count: 1},
|
||||
{name: "🍉", count: 1},
|
||||
]
|
||||
|
||||
const fn = (d) => d.count
|
||||
const data = d3.pie().value(fn)(fruits)
|
||||
|
||||
const arc = d3.arc()
|
||||
.innerRadius(210)
|
||||
.outerRadius(310)
|
||||
.padRadius(300)
|
||||
.padAngle(2 / 300)
|
||||
.cornerRadius(8)
|
||||
|
||||
const js = d3.select("#js")
|
||||
js.select(".loading").remove()
|
||||
|
||||
const svg = js
|
||||
.append("svg")
|
||||
.attr("viewBox", "-320 -320 640 640")
|
||||
.attr("width", "400")
|
||||
.attr("height", "400")
|
||||
|
||||
for (const d of data) {
|
||||
svg.append("path")
|
||||
.style("fill", "steelblue")
|
||||
.attr("d", arc(d))
|
||||
|
||||
const text = svg.append("text")
|
||||
.style("fill", "white")
|
||||
.attr("transform", `translate(${arc.centroid(d).join(",")})`)
|
||||
.attr("text-anchor", "middle")
|
||||
|
||||
text.append("tspan")
|
||||
.style("font-size", "24")
|
||||
.attr("x", "0").text(d.data.name)
|
||||
|
||||
text.append("tspan")
|
||||
.style("font-size", "18")
|
||||
.attr("x", "0")
|
||||
.attr("dy", "1.3em")
|
||||
.text(d.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<py-script>
|
||||
from pyodide.ffi import create_proxy, to_js
|
||||
import d3
|
||||
|
||||
fruits = [
|
||||
dict(name="🍊", count=21),
|
||||
dict(name="🍇", count=13),
|
||||
dict(name="🍏", count=8),
|
||||
dict(name="🍌", count=5),
|
||||
dict(name="🍐", count=3),
|
||||
dict(name="🍋", count=2),
|
||||
dict(name="🍎", count=1),
|
||||
dict(name="🍉", count=1),
|
||||
]
|
||||
|
||||
fn = create_proxy(lambda d, *_: d["count"])
|
||||
data = d3.pie().value(fn)(to_js(fruits))
|
||||
|
||||
arc = (d3.arc()
|
||||
.innerRadius(210)
|
||||
.outerRadius(310)
|
||||
.padRadius(300)
|
||||
.padAngle(2 / 300)
|
||||
.cornerRadius(8))
|
||||
|
||||
py = d3.select("#py")
|
||||
py.select(".loading").remove()
|
||||
|
||||
svg = (py
|
||||
.append("svg")
|
||||
.attr("viewBox", "-320 -320 640 640")
|
||||
.attr("width", "400")
|
||||
.attr("height", "400"))
|
||||
|
||||
for d in data:
|
||||
d_py = d.to_py()
|
||||
|
||||
(svg.append("path")
|
||||
.style("fill", "steelblue")
|
||||
.attr("d", arc(d)))
|
||||
|
||||
text = (svg.append("text")
|
||||
.style("fill", "white")
|
||||
.attr("transform", f"translate({arc.centroid(d).join(',')})")
|
||||
.attr("text-anchor", "middle"))
|
||||
|
||||
(text.append("tspan")
|
||||
.style("font-size", "24")
|
||||
.attr("x", "0")
|
||||
.text(d_py["data"]["name"]))
|
||||
|
||||
(text.append("tspan")
|
||||
.style("font-size", "18")
|
||||
.attr("x", "0")
|
||||
.attr("dy", "1.3em")
|
||||
.text(d_py["value"]))
|
||||
</py-script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
@@ -1,51 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Folium</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<py-config>
|
||||
packages = [
|
||||
"folium",
|
||||
"pandas"
|
||||
]
|
||||
</py-config>
|
||||
</head>
|
||||
<body>
|
||||
<div id="folium" style="width: 100%; height: 100%"></div>
|
||||
<py-script output="folium">
|
||||
import folium
|
||||
import json
|
||||
import pandas as pd
|
||||
|
||||
from pyodide.http import open_url
|
||||
|
||||
url = (
|
||||
"https://raw.githubusercontent.com/python-visualization/folium/master/examples/data"
|
||||
)
|
||||
state_geo = f"{url}/us-states.json"
|
||||
state_unemployment = f"{url}/US_Unemployment_Oct2012.csv"
|
||||
state_data = pd.read_csv(open_url(state_unemployment))
|
||||
geo_json = json.loads(open_url(state_geo).read())
|
||||
|
||||
m = folium.Map(location=[48, -102], zoom_start=3)
|
||||
|
||||
folium.Choropleth(
|
||||
geo_data=geo_json,
|
||||
name="choropleth",
|
||||
data=state_data,
|
||||
columns=["State", "Unemployment"],
|
||||
key_on="feature.id",
|
||||
fill_color="YlGn",
|
||||
fill_opacity=0.7,
|
||||
line_opacity=0.2,
|
||||
legend_name="Unemployment Rate (%)",
|
||||
).add_to(m)
|
||||
|
||||
folium.LayerControl().add_to(m)
|
||||
|
||||
m
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,139 +0,0 @@
|
||||
import numpy as np
|
||||
from numpy.polynomial import Polynomial
|
||||
|
||||
|
||||
def mandelbrot(
|
||||
width: int,
|
||||
height: int,
|
||||
*,
|
||||
x: float = -0.5,
|
||||
y: float = 0,
|
||||
zoom: int = 1,
|
||||
max_iterations: int = 100
|
||||
) -> np.array:
|
||||
"""
|
||||
https://www.learnpythonwithrune.org/numpy-compute-mandelbrot-set-by-vectorization
|
||||
"""
|
||||
# To make navigation easier we calculate these values
|
||||
x_width, y_height = 1.5, 1.5 * height / width
|
||||
x_from, x_to = x - x_width / zoom, x + x_width / zoom
|
||||
y_from, y_to = y - y_height / zoom, y + y_height / zoom
|
||||
|
||||
# Here the actual algorithm starts
|
||||
x = np.linspace(x_from, x_to, width).reshape((1, width))
|
||||
y = np.linspace(y_from, y_to, height).reshape((height, 1))
|
||||
c = x + 1j * y
|
||||
|
||||
# Initialize z to all zero
|
||||
z = np.zeros(c.shape, dtype=np.complex128)
|
||||
|
||||
# To keep track in which iteration the point diverged
|
||||
div_time = np.zeros(z.shape, dtype=int)
|
||||
|
||||
# To keep track on which points did not converge so far
|
||||
m = np.full(c.shape, True, dtype=bool)
|
||||
for i in range(max_iterations):
|
||||
z[m] = z[m] ** 2 + c[m]
|
||||
diverged = np.greater(
|
||||
np.abs(z), 2, out=np.full(c.shape, False), where=m
|
||||
) # Find diverging
|
||||
div_time[diverged] = i # set the value of the diverged iteration number
|
||||
m[np.abs(z) > 2] = False # to remember which have diverged
|
||||
|
||||
return div_time
|
||||
|
||||
|
||||
def julia(
|
||||
width: int,
|
||||
height: int,
|
||||
*,
|
||||
c: complex = -0.4 + 0.6j,
|
||||
x: float = 0,
|
||||
y: float = 0,
|
||||
zoom: int = 1,
|
||||
max_iterations: int = 100
|
||||
) -> np.array:
|
||||
"""
|
||||
https://www.learnpythonwithrune.org/numpy-calculate-the-julia-set-with-vectorization
|
||||
"""
|
||||
# To make navigation easier we calculate these values
|
||||
x_width, y_height = 1.5, 1.5 * height / width
|
||||
x_from, x_to = x - x_width / zoom, x + x_width / zoom
|
||||
y_from, y_to = y - y_height / zoom, y + y_height / zoom
|
||||
|
||||
# Here the actual algorithm starts
|
||||
x = np.linspace(x_from, x_to, width).reshape((1, width))
|
||||
y = np.linspace(y_from, y_to, height).reshape((height, 1))
|
||||
z = x + 1j * y
|
||||
|
||||
# Initialize z to all zero
|
||||
c = np.full(z.shape, c)
|
||||
|
||||
# To keep track in which iteration the point diverged
|
||||
div_time = np.zeros(z.shape, dtype=int)
|
||||
|
||||
# To keep track on which points did not converge so far
|
||||
m = np.full(c.shape, True, dtype=bool)
|
||||
for i in range(max_iterations):
|
||||
z[m] = z[m] ** 2 + c[m]
|
||||
m[np.abs(z) > 2] = False
|
||||
div_time[m] = i
|
||||
|
||||
return div_time
|
||||
|
||||
|
||||
Range = tuple[float, float]
|
||||
|
||||
|
||||
def newton(
|
||||
width: int,
|
||||
height: int,
|
||||
*,
|
||||
p: Polynomial,
|
||||
a: complex,
|
||||
xr: Range = (-2.5, 1),
|
||||
yr: Range = (-1, 1),
|
||||
max_iterations: int = 100
|
||||
) -> tuple[np.array, np.array]:
|
||||
""" """
|
||||
# To make navigation easier we calculate these values
|
||||
x_from, x_to = xr
|
||||
y_from, y_to = yr
|
||||
|
||||
# Here the actual algorithm starts
|
||||
x = np.linspace(x_from, x_to, width).reshape((1, width))
|
||||
y = np.linspace(y_from, y_to, height).reshape((height, 1))
|
||||
z = x + 1j * y
|
||||
|
||||
# Compute the derivative
|
||||
dp = p.deriv()
|
||||
|
||||
# Compute roots
|
||||
roots = p.roots()
|
||||
epsilon = 1e-5
|
||||
|
||||
# Set the initial conditions
|
||||
a = np.full(z.shape, a)
|
||||
|
||||
# To keep track in which iteration the point diverged
|
||||
div_time = np.zeros(z.shape, dtype=int)
|
||||
|
||||
# To keep track on which points did not converge so far
|
||||
m = np.full(a.shape, True, dtype=bool)
|
||||
|
||||
# To keep track which root each point converged to
|
||||
r = np.full(a.shape, 0, dtype=int)
|
||||
|
||||
for i in range(max_iterations):
|
||||
z[m] = z[m] - a[m] * p(z[m]) / dp(z[m])
|
||||
|
||||
for j, root in enumerate(roots):
|
||||
converged = (np.abs(z.real - root.real) < epsilon) & (
|
||||
np.abs(z.imag - root.imag) < epsilon
|
||||
)
|
||||
m[converged] = False
|
||||
r[converged] = j + 1
|
||||
|
||||
div_time[m] = i
|
||||
|
||||
return div_time, r
|
||||
2
examples/handtrack/lib/handtrack.min.js
vendored
2
examples/handtrack/lib/handtrack.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,122 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
|
||||
<title>Svelte app</title>
|
||||
|
||||
<link rel="icon" type="image/png" href="../favicon.png" />
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<py-script>
|
||||
from js import handTrack, requestAnimationFrame
|
||||
from pyodide import create_once_callable
|
||||
import asyncio
|
||||
|
||||
context = canvas.element.getContext("2d")
|
||||
|
||||
isVideo = False
|
||||
model = None
|
||||
|
||||
modelParams = {
|
||||
"flipHorizontal": True, # flip e.g for video
|
||||
"maxNumBoxes": 20, # maximum number of boxes to detect
|
||||
"iouThreshold": 0.5, # ioU threshold for non-max suppression
|
||||
"scoreThreshold": 0.6, # confidence threshold for predictions.
|
||||
}
|
||||
|
||||
def toggle_video(evt):
|
||||
global isVideo
|
||||
if (not isVideo):
|
||||
update_note.write("Starting video")
|
||||
pyscript.run_until_complete(start_video())
|
||||
else:
|
||||
update_note.write("Stopping video")
|
||||
handTrack.stopVideo(video.element)
|
||||
isVideo = False
|
||||
update_note.write("Video stopped")
|
||||
|
||||
async def start_video():
|
||||
global isVideo
|
||||
update_note.write("Inside sstart video")
|
||||
status = await handTrack.startVideo(video.element)
|
||||
console.log("video started", status)
|
||||
if status:
|
||||
update_note.write("Video started. Now tracking")
|
||||
isVideo = True
|
||||
console.log( "Calling RUN DETECTION")
|
||||
y = await run_detection()
|
||||
else:
|
||||
update_note.write( "Please enable video")
|
||||
|
||||
def sync_run_detection(evt):
|
||||
pyscript.run_until_complete(run_detection())
|
||||
|
||||
async def run_detection():
|
||||
console.log("in RUN DETECTION: ");
|
||||
global model
|
||||
global isVideo
|
||||
|
||||
console.log("...1")
|
||||
|
||||
predictions = await model.detect(video.element)
|
||||
console.log("done...1")
|
||||
console.log("Predictions: ", predictions);
|
||||
model.renderPredictions(predictions, canvas.element, context, video.element);
|
||||
console.log("is Video?", isVideo)
|
||||
if (isVideo):
|
||||
console.log("requestingAnimation!")
|
||||
await requestAnimationFrame(create_once_callable(sync_run_detection));
|
||||
console.log("...2")
|
||||
|
||||
def run_detection_image(img):
|
||||
console.log("in RUN DETECTION IMAGE", predictions);
|
||||
global model
|
||||
def detect(predition):
|
||||
console.log("Predictions: ", predictions);
|
||||
model.renderPredictions(predictions, canvas, context, img);
|
||||
console.log("...3")
|
||||
model.detect(img).then(detect)
|
||||
console.log("...4")
|
||||
|
||||
def handle_model(lmodel):
|
||||
global model
|
||||
model = lmodel
|
||||
update_note.write("Loaded Model!")
|
||||
|
||||
async def start():
|
||||
console.log("creating x")
|
||||
console.log("calling x")
|
||||
model = await handTrack.load(modelParams)#.then(handle_model)
|
||||
console.log("loaded model!")
|
||||
console.log(model)
|
||||
handle_model(model)
|
||||
print(dir(x))
|
||||
print(x)
|
||||
|
||||
pyscript.run_until_complete(start())
|
||||
|
||||
#});
|
||||
|
||||
</py-script>
|
||||
|
||||
<div class="mb10">
|
||||
<button id="trackbutton" class="bx--btn bx--btn--secondary" type="button" py-onClick="toggle_video()">
|
||||
Toggle Video
|
||||
</button>
|
||||
<button id="nextimagebutton" class="mt10 bx--btn bx--btn--secondary" type="button" disabled>
|
||||
Next Image
|
||||
</button>
|
||||
<div id="update-note" py-mount class="updatenote mt10">loading model ..</div>
|
||||
</div>
|
||||
<div>
|
||||
<video autoplay="autoplay" id="myvideo" py-mount="video"></video>
|
||||
<canvas id="canvas" py-mount class="border canvasbox"></canvas>
|
||||
</div>
|
||||
<script src="lib/handtrack.min.js"> </script>
|
||||
</html>
|
||||
@@ -1,24 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
|
||||
<title>PyScript Hello World</title>
|
||||
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
Hello world! <br>
|
||||
This is the current date and time, as computed by Python:
|
||||
<py-script>
|
||||
from datetime import datetime
|
||||
now = datetime.now()
|
||||
now.strftime("%m/%d/%Y, %H:%M:%S")
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,290 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>PyScript demo</title>
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<link rel="stylesheet" href="./assets/css/main.css" />
|
||||
<link rel="stylesheet" href="./assets/css/index.css" />
|
||||
</head>
|
||||
|
||||
<body class="container">
|
||||
<h1 class="title-main">PyScript demos</h1>
|
||||
<section class="example">
|
||||
<h2>Basic examples</h2>
|
||||
<div class="container-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./hello_world.html" target="_blank">
|
||||
<h2>Hello world</h2>
|
||||
</a>
|
||||
<p>
|
||||
A static demo of the <code><py-script></code> tag
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./simple_clock.html" target="_blank">
|
||||
<h2>Simple clock</h2>
|
||||
</a>
|
||||
<p>
|
||||
A dynamic demo of the <code><py-script></code> tag
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./repl.html" target="_blank">
|
||||
<h2>REPL</h2>
|
||||
</a>
|
||||
<p>
|
||||
A Python REPL (Read Eval Print Loop)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./repl2.html" target="_blank">
|
||||
<h2>REPL2</h2>
|
||||
</a>
|
||||
<p>
|
||||
A Python REPL (Read Eval Print Loop) with slightly better formatting
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./todo.html" target="_blank">
|
||||
<h2>TODO App</h2>
|
||||
</a>
|
||||
<p>
|
||||
Simple TODO App
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./todo-pylist.html" target="_blank">
|
||||
<h2>PyScript Native TODO App</h2>
|
||||
</a>
|
||||
<p>
|
||||
Simple TODO App using <code><py-list></code>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="example">
|
||||
<h2>MIME Rendering</h2>
|
||||
<div class="container-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./matplotlib.html" target="_blank">
|
||||
<h2>Matplotlib</h2>
|
||||
</a>
|
||||
<p>
|
||||
Demonstrates rendering a <a href="https://matplotlib.org/" target="_blank">Matplotlib</a> figure as output of the py-script tag
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./altair.html" target="_blank">
|
||||
<h2>
|
||||
Altair
|
||||
</h2>
|
||||
</a>
|
||||
<p>
|
||||
Demonstrates rendering a <a href="https://altair-viz.github.io/" target="_blank">Altair</a> plot as output of the py-script tag
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./folium.html" target="_blank">
|
||||
<h2>
|
||||
Folium
|
||||
</h2>
|
||||
</a>
|
||||
<p>
|
||||
Demonstrates rendering a
|
||||
<a href="https://python-visualization.github.io/folium/" target="_blank">Folium</a>
|
||||
map as output of the py-script tag
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="example">
|
||||
<h2>JS Interaction</h2>
|
||||
<div class="container-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./d3.html" target="_blank">
|
||||
<h2>
|
||||
Simple d3 visualization
|
||||
</h2>
|
||||
</a>
|
||||
<p>
|
||||
Minimal <a href="https://d3js.org/" target="_blank">D3</a>
|
||||
demo demonstrating how to create a visualization
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./webgl/raycaster/index.html" target="_blank">
|
||||
<h2>
|
||||
Webgl Icosahedron Example
|
||||
</h2>
|
||||
</a>
|
||||
<p>
|
||||
Demo showing how a Simple <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API" target="_blank">WebGL</a>
|
||||
scene would work in PyScript</code> tag
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="example">
|
||||
<h2>Visualizations & Dashboards</h2>
|
||||
<div class="container-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./bokeh.html" target="_blank">
|
||||
<h2>
|
||||
Simple Static Bokeh Plot
|
||||
</h2>
|
||||
</a>
|
||||
<p>
|
||||
Minimal Bokeh demo demonstrating how to create a simple
|
||||
<a href="https://bokeh.org/" target="_blank">Bokeh</a>
|
||||
plot from code
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./bokeh_interactive.html" target="_blank">
|
||||
<h2 class="text-2xl font-bold text-blue-600">
|
||||
Bokeh Interactive
|
||||
</h2>
|
||||
</a>
|
||||
<p>
|
||||
Interactive demo using a
|
||||
<a href="https://bokeh.org/" target="_blank">Bokeh</a>
|
||||
slider widget to dynamically change a value in the page
|
||||
WARNING: This examples takes a little longer to load. So be patient :)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./panel_kmeans.html" target="_blank">
|
||||
<h2 class="text-2xl font-bold text-blue-600">
|
||||
KMeans Demo in Panel
|
||||
</h2>
|
||||
</a>
|
||||
<p>
|
||||
Interactive KMeans Chart using
|
||||
<a href="https://panel.holoviz.org/" target="_blank">Panel</a>
|
||||
WARNING: This examples takes a little longer to load. So be patient :)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./panel_stream.html" target="_blank">
|
||||
<h2 class="text-2xl font-bold text-blue-600">
|
||||
Streaming Demo in Panel
|
||||
</h2>
|
||||
</a>
|
||||
<p>
|
||||
Interactive Streaming Table and Bokeh plot using
|
||||
<a href="https://panel.holoviz.org/" target="_blank">Panel</a>
|
||||
WARNING: This examples takes a little longer to load. So be patient :)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./panel.html" target="_blank">
|
||||
<h2 class="text-3xl font-bold text-blue-600">
|
||||
Simple Panel Demo
|
||||
</h2>
|
||||
</a>
|
||||
<p>
|
||||
Simple demo showing
|
||||
<a href="https://panel.holoviz.org/" target="_blank">Panel</a>
|
||||
widgets interacting with parts of the page
|
||||
WARNING: This examples takes a little longer to load. So be patient :)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./panel_deckgl.html" target="_blank">
|
||||
<h2 class="text-2xl font-bold text-blue-600">
|
||||
NYC Taxi Data Panel DeckGL Demo
|
||||
</h2>
|
||||
</a>
|
||||
<p>
|
||||
Interactive application exploring the NYC Taxi dataset using
|
||||
<a href="https://panel.holoviz.org/" target="_blank">Panel</a> and <a href="https://deck.gl/" target="_blank">DeckGL</a>
|
||||
WARNING: This examples takes a little longer to load. So be patient :)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./toga/freedom.html" target="_blank">
|
||||
<h2 class="text-2xl font-bold text-blue-600">
|
||||
Freedom Units!
|
||||
</h2>
|
||||
</a>
|
||||
<p>
|
||||
A <a href="https://beeware.org/project/projects/libraries/toga/" target="_blank">Toga</a>
|
||||
application (a Fahrenheit to Celsius converter), rendered as a Single Page App
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./numpy_canvas_fractals.html" target="_blank">
|
||||
<h2 class="text-2xl font-bold text-blue-600">
|
||||
Fractals with NumPy and canvas
|
||||
</h2>
|
||||
</a>
|
||||
<p>
|
||||
Visualization of Mandelbrot and Julia sets with
|
||||
<a href="https://numpy.org/" target="_blank">Numpy</a> and
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API" target="_blank">
|
||||
HTML5 canvas
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 7.3 KiB |
@@ -1,32 +0,0 @@
|
||||
html, body, ul, li {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: block;
|
||||
width: 762;
|
||||
margin: 0 auto;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
p {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
html {
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.info {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
|
||||
var Bcoin = Mario.Bcoin = function(pos) {
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: level.bcoinSprite(),
|
||||
hitbox: [0,0,16,16]
|
||||
});
|
||||
}
|
||||
|
||||
Mario.Util.inherits(Bcoin, Mario.Entity);
|
||||
|
||||
//I'm not sure whether it makes sense to use an array for vel and acc here
|
||||
//in order to keep with convention, or to just use a single value, since
|
||||
//it's literally impossible for these to move left or right.
|
||||
Bcoin.prototype.spawn = function() {
|
||||
sounds.coin.currentTime = 0.05;
|
||||
sounds.coin.play();
|
||||
this.idx = level.items.length;
|
||||
level.items.push(this);
|
||||
this.active = true;
|
||||
this.vel = -12;
|
||||
this.targetpos = this.pos[1] - 32;
|
||||
}
|
||||
|
||||
Bcoin.prototype.update = function(dt) {
|
||||
if (!this.active) return;
|
||||
|
||||
if (this.vel > 0 && this.pos[1] >= this.targetpos) {
|
||||
player.coins += 1;
|
||||
//spawn a score thingy.
|
||||
delete level.items[this.idx];
|
||||
}
|
||||
|
||||
this.acc = 0.75;
|
||||
this.vel += this.acc;
|
||||
this.pos[1] += this.vel;
|
||||
this.sprite.update(dt);
|
||||
}
|
||||
|
||||
Bcoin.prototype.checkCollisions = function() {;}
|
||||
|
||||
})();
|
||||
@@ -1,81 +0,0 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
|
||||
//TODO: clean up the logic for sprite switching.
|
||||
//TODO: There's a weird bug with the collision logic. Look into it.
|
||||
|
||||
var Block = Mario.Block = function(options) {
|
||||
this.item = options.item;
|
||||
this.usedSprite = options.usedSprite;
|
||||
this.bounceSprite = options.bounceSprite;
|
||||
this.breakable = options.breakable;
|
||||
|
||||
Mario.Entity.call(this, {
|
||||
pos: options.pos,
|
||||
sprite: options.sprite,
|
||||
hitbox: [0,0,16,16]
|
||||
});
|
||||
|
||||
this.standing = true;
|
||||
}
|
||||
|
||||
Mario.Util.inherits(Block, Mario.Floor);
|
||||
|
||||
Block.prototype.break = function() {
|
||||
sounds.breakBlock.play();
|
||||
(new Mario.Rubble()).spawn(this.pos);
|
||||
var x = this.pos[0] / 16, y = this.pos[1] / 16;
|
||||
delete level.blocks[y][x];
|
||||
}
|
||||
|
||||
Block.prototype.bonk = function(power) {
|
||||
sounds.bump.play();
|
||||
if (power > 0 && this.breakable) {
|
||||
this.break();
|
||||
} else if (this.standing){
|
||||
this.standing = false;
|
||||
if (this.item) {
|
||||
this.item.spawn();
|
||||
this.item = null;
|
||||
}
|
||||
this.opos = [];
|
||||
this.opos[0] = this.pos[0];
|
||||
this.opos[1] = this.pos[1];
|
||||
if (this.bounceSprite) {
|
||||
this.osprite = this.sprite;
|
||||
this.sprite = this.bounceSprite;
|
||||
} else {
|
||||
this.sprite = this.usedSprite;
|
||||
}
|
||||
|
||||
this.vel[1] = -2;
|
||||
}
|
||||
}
|
||||
|
||||
Block.prototype.update = function(dt, gameTime) {
|
||||
if (!this.standing) {
|
||||
if (this.pos[1] < this.opos[1] - 8) {
|
||||
this.vel[1] = 2;
|
||||
}
|
||||
if (this.pos[1] > this.opos[1]) {
|
||||
this.vel[1] = 0;
|
||||
this.pos = this.opos;
|
||||
if (this.osprite) {
|
||||
this.sprite = this.osprite;
|
||||
}
|
||||
this.standing = true;
|
||||
}
|
||||
} else {
|
||||
if (this.sprite === this.usedSprite) {
|
||||
var x = this.pos[0] / 16, y = this.pos[1] / 16;
|
||||
level.statics[y][x] = new Mario.Floor(this.pos, this.usedSprite);
|
||||
delete level.blocks[y][x];
|
||||
}
|
||||
}
|
||||
|
||||
this.pos[1] += this.vel[1];
|
||||
this.sprite.update(dt, gameTime);
|
||||
}
|
||||
|
||||
})();
|
||||
@@ -1,47 +0,0 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
|
||||
var Coin = Mario.Coin = function(pos, sprite) {
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: sprite,
|
||||
hitbox: [0,0,16,16]
|
||||
});
|
||||
this.idx = level.items.length
|
||||
}
|
||||
|
||||
Mario.Util.inherits(Coin, Mario.Entity);
|
||||
|
||||
Coin.prototype.isPlayerCollided = function() {
|
||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
||||
var hpos1 = [this.pos[0] + this.hitbox[0], this.pos[1] + this.hitbox[1]];
|
||||
var hpos2 = [player.pos[0] + player.hitbox[0], player.pos[1] + player.hitbox[1]];
|
||||
|
||||
//if the hitboxes actually overlap
|
||||
if (!(hpos1[0] > hpos2[0]+player.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
||||
if (!(hpos1[1] > hpos2[1]+player.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
||||
this.collect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Coin.prototype.render = function(ctx, vX, vY) {
|
||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
}
|
||||
|
||||
//money is not affected by gravity, you see.
|
||||
Coin.prototype.update = function(dt) {
|
||||
this.sprite.update(dt);
|
||||
}
|
||||
Coin.prototype.checkCollisions = function() {
|
||||
this.isPlayerCollided();
|
||||
}
|
||||
|
||||
Coin.prototype.collect = function() {
|
||||
sounds.coin.currentTime = 0.05;
|
||||
sounds.coin.play();
|
||||
player.coins += 1;
|
||||
delete level.items[this.idx]
|
||||
}
|
||||
})();
|
||||
@@ -1,34 +0,0 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
|
||||
var Entity = Mario.Entity = function(options) {
|
||||
this.vel = [0,0];
|
||||
this.acc = [0,0];
|
||||
this.standing = true;
|
||||
this.pos = options.pos;
|
||||
this.sprite = options.sprite;
|
||||
this.hitbox = options.hitbox;
|
||||
this.left = false;
|
||||
}
|
||||
|
||||
Entity.prototype.render = function(ctx, vX, vY) {
|
||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY)
|
||||
}
|
||||
|
||||
Entity.prototype.collideWall = function(wall) {
|
||||
//the wall will always be a 16x16 block with hitbox = [0,0,16,16].
|
||||
if (this.pos[0] > wall.pos[0]) {
|
||||
//from the right
|
||||
this.pos[0] = wall.pos[0] + wall.hitbox[2] - this.hitbox[0];
|
||||
this.vel[0] = Math.max(0, this.vel[0]);
|
||||
this.acc[0] = Math.max(0, this.acc[0]);
|
||||
} else {
|
||||
this.pos[0] = wall.pos[0] + wall.hitbox[0] - this.hitbox[2] - this.hitbox[0];
|
||||
this.vel[0] = Math.min(0, this.vel[0]);
|
||||
this.acc[0] = Math.min(0, this.acc[0]);
|
||||
}
|
||||
}
|
||||
|
||||
Entity.prototype.bump = function() {;}
|
||||
})();
|
||||
@@ -1,126 +0,0 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
|
||||
var Fireball = Mario.Fireball = function(pos) {
|
||||
this.hit = 0;
|
||||
this.standing = false;
|
||||
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: new Mario.Sprite('sprites/items.png', [96, 144], [8,8], 5, [0,1,2,3]),
|
||||
hitbox: [0,0,8,8]
|
||||
});
|
||||
}
|
||||
|
||||
Mario.Util.inherits(Fireball, Mario.Entity);
|
||||
|
||||
Fireball.prototype.spawn = function(left) {
|
||||
sounds.fireball.currentTime = 0;
|
||||
sounds.fireball.play();
|
||||
if (fireballs[0]) {
|
||||
this.idx = 1;
|
||||
fireballs[1] = this;
|
||||
} else {
|
||||
this.idx = 0;
|
||||
fireballs[0] = this;
|
||||
}
|
||||
this.vel[0] = (left ? -5 : 5);
|
||||
this.standing = false;
|
||||
this.vel[1] = 0;
|
||||
}
|
||||
|
||||
Fireball.prototype.render = function(ctx, vX, vY) {
|
||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
}
|
||||
|
||||
Fireball.prototype.update = function(dt) {
|
||||
if (this.hit == 1) {
|
||||
this.sprite.pos = [96, 160];
|
||||
this.sprite.size = [16,16];
|
||||
this.sprite.frames = [0,1,2];
|
||||
this.sprite.speed = 8;
|
||||
this.hit += 1;
|
||||
return;
|
||||
} else if (this.hit == 5) {
|
||||
delete fireballs[this.idx];
|
||||
player.fireballs -= 1;
|
||||
return;
|
||||
} else if (this.hit) {
|
||||
this.hit += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
//In retrospect, the way collision is being handled is RIDICULOUS
|
||||
//but I don't have to use some horrible kludge for this.
|
||||
if (this.standing) {
|
||||
this.standing = false;
|
||||
this.vel[1] = -4;
|
||||
}
|
||||
|
||||
this.acc[1] = 0.5;
|
||||
|
||||
this.vel[1] += this.acc[1];
|
||||
this.pos[0] += this.vel[0];
|
||||
this.pos[1] += this.vel[1];
|
||||
if (this.pos[0] < vX || this.pos[0] > vX + 256) {
|
||||
this.hit = 1;
|
||||
}
|
||||
this.sprite.update(dt);
|
||||
}
|
||||
|
||||
Fireball.prototype.collideWall = function() {
|
||||
if (!this.hit) this.hit = 1;
|
||||
}
|
||||
|
||||
Fireball.prototype.checkCollisions = function() {
|
||||
if (this.hit) return;
|
||||
var h = this.pos[1] % 16 < 8 ? 1 : 2;
|
||||
var w = this.pos[0] % 16 < 8 ? 1 : 2;
|
||||
|
||||
var baseX = Math.floor(this.pos[0] / 16);
|
||||
var baseY = Math.floor(this.pos[1] / 16);
|
||||
|
||||
if (baseY + h > 15) {
|
||||
delete fireballs[this.idx];
|
||||
player.fireballs -= 1;
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < h; i++) {
|
||||
for (var j = 0; j < w; j++) {
|
||||
if (level.statics[baseY + i][baseX + j]) {
|
||||
level.statics[baseY + i][baseX + j].isCollideWith(this);
|
||||
}
|
||||
if (level.blocks[baseY + i][baseX + j]) {
|
||||
level.blocks[baseY + i][baseX + j].isCollideWith(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var that = this;
|
||||
level.enemies.forEach(function(enemy){
|
||||
if (enemy.flipping || enemy.pos[0] - vX > 336){ //stop checking once we get to far away dudes.
|
||||
return;
|
||||
} else {
|
||||
that.isCollideWith(enemy);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Fireball.prototype.isCollideWith = function(ent) {
|
||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
||||
var hpos1 = [this.pos[0] + this.hitbox[0], this.pos[1] + this.hitbox[1]];
|
||||
var hpos2 = [ent.pos[0] + ent.hitbox[0], ent.pos[1] + ent.hitbox[1]];
|
||||
|
||||
//if the hitboxes actually overlap
|
||||
if (!(hpos1[0] > hpos2[0]+ent.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
||||
if (!(hpos1[1] > hpos2[1]+ent.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
||||
this.hit = 1;
|
||||
ent.bump();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Fireball.prototype.bump = function() {;}
|
||||
})();
|
||||
@@ -1,74 +0,0 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
|
||||
var Fireflower = Mario.Fireflower = function(pos) {
|
||||
this.spawning = false;
|
||||
this.waiting = 0;
|
||||
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: level.fireFlowerSprite,
|
||||
hitbox: [0,0,16,16]
|
||||
});
|
||||
}
|
||||
|
||||
Mario.Util.inherits(Fireflower, Mario.Entity);
|
||||
|
||||
Fireflower.prototype.render = function(ctx, vX, vY) {
|
||||
if (this.spawning > 1) return;
|
||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
}
|
||||
|
||||
Fireflower.prototype.spawn = function() {
|
||||
sounds.itemAppear.play();
|
||||
this.idx = level.items.length;
|
||||
level.items.push(this);
|
||||
this.spawning = 12;
|
||||
this.targetpos = [];
|
||||
this.targetpos[0] = this.pos[0];
|
||||
this.targetpos[1] = this.pos[1] - 16;
|
||||
}
|
||||
|
||||
Fireflower.prototype.update = function(dt) {
|
||||
if (this.spawning > 1) {
|
||||
this.spawning -= 1;
|
||||
if (this.spawning == 1) this.vel[1] = -.5;
|
||||
return;
|
||||
}
|
||||
if (this.spawning) {
|
||||
if (this.pos[1] <= this.targetpos[1]) {
|
||||
this.pos[1] = this.targetpos[1];
|
||||
this.vel[1] = 0;
|
||||
this.spawning = 0;
|
||||
}
|
||||
}
|
||||
|
||||
this.vel[1] += this.acc[1];
|
||||
this.pos[0] += this.vel[0];
|
||||
this.pos[1] += this.vel[1];
|
||||
this.sprite.update(dt);
|
||||
}
|
||||
|
||||
Fireflower.prototype.checkCollisions = function() {
|
||||
if (this.spawning) {return;}
|
||||
this.isPlayerCollided();
|
||||
}
|
||||
|
||||
Fireflower.prototype.isPlayerCollided = function() {
|
||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
||||
var hpos1 = [this.pos[0] + this.hitbox[0], this.pos[1] + this.hitbox[1]];
|
||||
var hpos2 = [player.pos[0] + player.hitbox[0], player.pos[1] + player.hitbox[1]];
|
||||
|
||||
//if the hitboxes actually overlap
|
||||
if (!(hpos1[0] > hpos2[0]+player.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
||||
if (!(hpos1[1] > hpos2[1]+player.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
||||
player.powerUp(this.idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//This should never be called, but just in case.
|
||||
Fireflower.prototype.bump = function() {;}
|
||||
|
||||
})();
|
||||
@@ -1,47 +0,0 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
|
||||
Flag = Mario.Flag = function(pos) {
|
||||
//afaik flags always have the same height and Y-position
|
||||
this.pos = [pos, 49];
|
||||
this.hitbox = [0,0,0,0];
|
||||
this.vel = [0,0];
|
||||
this.acc = [0,0];
|
||||
}
|
||||
|
||||
Flag.prototype.collideWall = function() {;
|
||||
}
|
||||
|
||||
Flag.prototype.update = function(dt){
|
||||
if (!this.done && this.pos[1] >= 170) {
|
||||
this.vel = [0,0];
|
||||
this.pos[1] = 170;
|
||||
player.exit();
|
||||
this.done = true;
|
||||
}
|
||||
this.pos[1] += this.vel[1];
|
||||
}
|
||||
|
||||
Flag.prototype.checkCollisions = function() {
|
||||
this.isPlayerCollided();
|
||||
}
|
||||
|
||||
Flag.prototype.isPlayerCollided = function() {
|
||||
if (this.hit) return;
|
||||
if (player.pos[0] + 8 >= this.pos[0]) {
|
||||
music.overworld.pause();
|
||||
sounds.flagpole.play();
|
||||
setTimeout(function() {
|
||||
music.clear.play();
|
||||
}, 2000);
|
||||
this.hit = true;
|
||||
player.flag();
|
||||
this.vel = [0, 2];
|
||||
}
|
||||
}
|
||||
|
||||
Flag.prototype.render = function() {
|
||||
level.flagpoleSprites[2].render(ctx, this.pos[0]-8, this.pos[1], vX, vY);
|
||||
}
|
||||
})();
|
||||
@@ -1,56 +0,0 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
|
||||
var Floor = Mario.Floor = function(pos, sprite) {
|
||||
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: sprite,
|
||||
hitbox: [0,0,16,16]
|
||||
});
|
||||
}
|
||||
|
||||
Mario.Util.inherits(Floor, Mario.Entity);
|
||||
|
||||
Floor.prototype.isCollideWith = function (ent) {
|
||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
||||
var hpos1 = [Math.floor(this.pos[0] + this.hitbox[0]), Math.floor(this.pos[1] + this.hitbox[1])];
|
||||
var hpos2 = [Math.floor(ent.pos[0] + ent.hitbox[0]), Math.floor(ent.pos[1] + ent.hitbox[1])];
|
||||
|
||||
//if the hitboxes actually overlap
|
||||
if (!(hpos1[0] > hpos2[0]+ent.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
||||
if (!(hpos1[1] > hpos2[1]+ent.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
||||
if (!this.standing) {
|
||||
ent.bump();
|
||||
} else {
|
||||
//if the entity is over the block, it's basically floor
|
||||
var center = hpos2[0] + ent.hitbox[2] / 2;
|
||||
if (Math.abs(hpos2[1] + ent.hitbox[3] - hpos1[1]) <= ent.vel[1]) {
|
||||
if (level.statics[(this.pos[1] / 16) - 1][this.pos[0] / 16]) {return};
|
||||
ent.vel[1] = 0;
|
||||
ent.pos[1] = hpos1[1] - ent.hitbox[3] - ent.hitbox[1];
|
||||
ent.standing = true;
|
||||
if (ent instanceof Mario.Player) {
|
||||
ent.jumping = 0;
|
||||
}
|
||||
} else if (Math.abs(hpos2[1] - hpos1[1] - this.hitbox[3]) > ent.vel[1] &&
|
||||
center + 2 >= hpos1[0] && center - 2 <= hpos1[0] + this.hitbox[2]) {
|
||||
//ent is under the block.
|
||||
ent.vel[1] = 0;
|
||||
ent.pos[1] = hpos1[1] + this.hitbox[3];
|
||||
if (ent instanceof Mario.Player) {
|
||||
this.bonk(ent.power);
|
||||
ent.jumping = 0;
|
||||
}
|
||||
} else {
|
||||
//entity is hitting it from the side, we're a wall
|
||||
ent.collideWall(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Floor.prototype.bonk = function() {;}
|
||||
})();
|
||||
@@ -1,241 +0,0 @@
|
||||
var requestAnimFrame = (function(){
|
||||
return window.requestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
window.oRequestAnimationFrame ||
|
||||
window.msRequestAnimationFrame ||
|
||||
function(callback){
|
||||
window.setTimeout(callback, 1000 / 60);
|
||||
};
|
||||
})();
|
||||
|
||||
//create the canvas
|
||||
var canvas = document.createElement("canvas");
|
||||
var ctx = canvas.getContext('2d');
|
||||
var updateables = [];
|
||||
var fireballs = [];
|
||||
var player = new Mario.Player([0,0]);
|
||||
|
||||
//we might have to get the size and calculate the scaling
|
||||
//but this method should let us make it however big.
|
||||
//Cool!
|
||||
//TODO: Automatically scale the game to work and look good on widescreen.
|
||||
//TODO: fiddling with scaled sprites looks BETTER, but not perfect. Hmm.
|
||||
canvas.width = 762;
|
||||
canvas.height = 720;
|
||||
ctx.scale(3,3);
|
||||
document.body.appendChild(canvas);
|
||||
|
||||
//viewport
|
||||
var vX = 0,
|
||||
vY = 0,
|
||||
vWidth = 256,
|
||||
vHeight = 240;
|
||||
|
||||
//load our images
|
||||
resources.load([
|
||||
'sprites/player.png',
|
||||
'sprites/enemy.png',
|
||||
'sprites/tiles.png',
|
||||
'sprites/playerl.png',
|
||||
'sprites/items.png',
|
||||
'sprites/enemyr.png',
|
||||
]);
|
||||
|
||||
resources.onReady(init);
|
||||
var level;
|
||||
var sounds;
|
||||
var music;
|
||||
|
||||
//initialize
|
||||
var lastTime;
|
||||
function init() {
|
||||
music = {
|
||||
overworld: new Audio('sounds/aboveground_bgm.ogg'),
|
||||
underground: new Audio('sounds/underground_bgm.ogg'),
|
||||
clear: new Audio('sounds/stage_clear.wav'),
|
||||
death: new Audio('sounds/mariodie.wav')
|
||||
};
|
||||
sounds = {
|
||||
smallJump: new Audio('sounds/jump-small.wav'),
|
||||
bigJump: new Audio('sounds/jump-super.wav'),
|
||||
breakBlock: new Audio('sounds/breakblock.wav'),
|
||||
bump: new Audio('sounds/bump.wav'),
|
||||
coin: new Audio('sounds/coin.wav'),
|
||||
fireball: new Audio('sounds/fireball.wav'),
|
||||
flagpole: new Audio('sounds/flagpole.wav'),
|
||||
kick: new Audio('sounds/kick.wav'),
|
||||
pipe: new Audio('sounds/pipe.wav'),
|
||||
itemAppear: new Audio('sounds/itemAppear.wav'),
|
||||
powerup: new Audio('sounds/powerup.wav'),
|
||||
stomp: new Audio('sounds/stomp.wav')
|
||||
};
|
||||
Mario.oneone();
|
||||
lastTime = Date.now();
|
||||
main();
|
||||
}
|
||||
|
||||
var gameTime = 0;
|
||||
|
||||
//set up the game loop
|
||||
function main() {
|
||||
var now = Date.now();
|
||||
var dt = (now - lastTime) / 1000.0;
|
||||
|
||||
update(dt);
|
||||
render();
|
||||
|
||||
lastTime = now;
|
||||
requestAnimFrame(main);
|
||||
}
|
||||
|
||||
function update(dt) {
|
||||
gameTime += dt;
|
||||
|
||||
handleInput(dt);
|
||||
updateEntities(dt, gameTime);
|
||||
|
||||
checkCollisions();
|
||||
}
|
||||
|
||||
function handleInput(dt) {
|
||||
if (player.piping || player.dying || player.noInput) return; //don't accept input
|
||||
|
||||
if (input.isDown('RUN')){
|
||||
player.run();
|
||||
} else {
|
||||
player.noRun();
|
||||
}
|
||||
if (input.isDown('JUMP')) {
|
||||
player.jump();
|
||||
} else {
|
||||
//we need this to handle the timing for how long you hold it
|
||||
player.noJump();
|
||||
}
|
||||
|
||||
if (input.isDown('DOWN')) {
|
||||
player.crouch();
|
||||
} else {
|
||||
player.noCrouch();
|
||||
}
|
||||
|
||||
if (input.isDown('LEFT')) { // 'd' or left arrow
|
||||
player.moveLeft();
|
||||
}
|
||||
else if (input.isDown('RIGHT')) { // 'k' or right arrow
|
||||
player.moveRight();
|
||||
} else {
|
||||
player.noWalk();
|
||||
}
|
||||
}
|
||||
|
||||
//update all the moving stuff
|
||||
function updateEntities(dt, gameTime) {
|
||||
player.update(dt, vX);
|
||||
updateables.forEach (function(ent) {
|
||||
ent.update(dt, gameTime);
|
||||
});
|
||||
|
||||
//This should stop the jump when he switches sides on the flag.
|
||||
if (player.exiting) {
|
||||
if (player.pos[0] > vX + 96)
|
||||
vX = player.pos[0] - 96
|
||||
}else if (level.scrolling && player.pos[0] > vX + 80) {
|
||||
vX = player.pos[0] - 80;
|
||||
}
|
||||
|
||||
if (player.powering.length !== 0 || player.dying) { return; }
|
||||
level.items.forEach (function(ent) {
|
||||
ent.update(dt);
|
||||
});
|
||||
|
||||
level.enemies.forEach (function(ent) {
|
||||
ent.update(dt, vX);
|
||||
});
|
||||
|
||||
fireballs.forEach(function(fireball) {
|
||||
fireball.update(dt);
|
||||
});
|
||||
level.pipes.forEach (function(pipe) {
|
||||
pipe.update(dt);
|
||||
});
|
||||
}
|
||||
|
||||
//scan for collisions
|
||||
function checkCollisions() {
|
||||
if (player.powering.length !== 0 || player.dying) { return; }
|
||||
player.checkCollisions();
|
||||
|
||||
//Apparently for each will just skip indices where things were deleted.
|
||||
level.items.forEach(function(item) {
|
||||
item.checkCollisions();
|
||||
});
|
||||
level.enemies.forEach (function(ent) {
|
||||
ent.checkCollisions();
|
||||
});
|
||||
fireballs.forEach(function(fireball){
|
||||
fireball.checkCollisions();
|
||||
});
|
||||
level.pipes.forEach (function(pipe) {
|
||||
pipe.checkCollisions();
|
||||
});
|
||||
}
|
||||
|
||||
//draw the game!
|
||||
function render() {
|
||||
updateables = [];
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.fillStyle = level.background;
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
//scenery gets drawn first to get layering right.
|
||||
for(var i = 0; i < 15; i++) {
|
||||
for (var j = Math.floor(vX / 16) - 1; j < Math.floor(vX / 16) + 20; j++){
|
||||
if (level.scenery[i][j]) {
|
||||
renderEntity(level.scenery[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//then items
|
||||
level.items.forEach (function (item) {
|
||||
renderEntity(item);
|
||||
});
|
||||
|
||||
level.enemies.forEach (function(enemy) {
|
||||
renderEntity(enemy);
|
||||
});
|
||||
|
||||
|
||||
|
||||
fireballs.forEach(function(fireball) {
|
||||
renderEntity(fireball);
|
||||
})
|
||||
|
||||
//then we draw every static object.
|
||||
for(var i = 0; i < 15; i++) {
|
||||
for (var j = Math.floor(vX / 16) - 1; j < Math.floor(vX / 16) + 20; j++){
|
||||
if (level.statics[i][j]) {
|
||||
renderEntity(level.statics[i][j]);
|
||||
}
|
||||
if (level.blocks[i][j]) {
|
||||
renderEntity(level.blocks[i][j]);
|
||||
updateables.push(level.blocks[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//then the player
|
||||
if (player.invincibility % 2 === 0) {
|
||||
renderEntity(player);
|
||||
}
|
||||
|
||||
//Mario goes INTO pipes, so naturally they go after.
|
||||
level.pipes.forEach (function(pipe) {
|
||||
renderEntity(pipe);
|
||||
});
|
||||
}
|
||||
|
||||
function renderEntity(entity) {
|
||||
entity.render(ctx, vX, vY);
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
|
||||
//TODO: On console the hitbox is smaller. Measure it and edit this.
|
||||
|
||||
var Goomba = Mario.Goomba = function(pos, sprite) {
|
||||
this.dying = false;
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: sprite,
|
||||
hitbox: [0,0,16,16]
|
||||
});
|
||||
this.vel[0] = -0.5;
|
||||
this.idx = level.enemies.length;
|
||||
};
|
||||
|
||||
Goomba.prototype.render = function(ctx, vX, vY) {
|
||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
};
|
||||
|
||||
Goomba.prototype.update = function(dt, vX) {
|
||||
if (this.pos[0] - vX > 336) { //if we're too far away, do nothing.
|
||||
return;
|
||||
} else if (this.pos[0] - vX < -32) {
|
||||
delete level.enemies[this.idx];
|
||||
}
|
||||
|
||||
if (this.dying) {
|
||||
this.dying -= 1;
|
||||
if (!this.dying) {
|
||||
delete level.enemies[this.idx];
|
||||
}
|
||||
}
|
||||
this.acc[1] = 0.2;
|
||||
this.vel[1] += this.acc[1];
|
||||
this.pos[0] += this.vel[0];
|
||||
this.pos[1] += this.vel[1];
|
||||
this.sprite.update(dt);
|
||||
};
|
||||
|
||||
Goomba.prototype.collideWall = function() {
|
||||
this.vel[0] = -this.vel[0];
|
||||
};
|
||||
|
||||
Goomba.prototype.checkCollisions = function() {
|
||||
if (this.flipping) {
|
||||
return;
|
||||
}
|
||||
|
||||
var h = this.pos[1] % 16 === 0 ? 1 : 2;
|
||||
var w = this.pos[0] % 16 === 0 ? 1 : 2;
|
||||
|
||||
var baseX = Math.floor(this.pos[0] / 16);
|
||||
var baseY = Math.floor(this.pos[1] / 16);
|
||||
|
||||
if (baseY + h > 15) {
|
||||
delete level.enemies[this.idx];
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < h; i++) {
|
||||
for (var j = 0; j < w; j++) {
|
||||
if (level.statics[baseY + i][baseX + j]) {
|
||||
level.statics[baseY + i][baseX + j].isCollideWith(this);
|
||||
}
|
||||
if (level.blocks[baseY + i][baseX + j]) {
|
||||
level.blocks[baseY + i][baseX + j].isCollideWith(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
var that = this;
|
||||
level.enemies.forEach(function(enemy){
|
||||
if (enemy === that) { //don't check collisions with ourselves.
|
||||
return;
|
||||
} else if (enemy.pos[0] - vX > 336){ //stop checking once we get to far away dudes.
|
||||
return;
|
||||
} else {
|
||||
that.isCollideWith(enemy);
|
||||
}
|
||||
});
|
||||
this.isCollideWith(player);
|
||||
};
|
||||
|
||||
Goomba.prototype.isCollideWith = function(ent) {
|
||||
if (ent instanceof Mario.Player && (this.dying || ent.invincibility)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
||||
var hpos1 = [this.pos[0] + this.hitbox[0], this.pos[1] + this.hitbox[1]];
|
||||
var hpos2 = [ent.pos[0] + ent.hitbox[0], ent.pos[1] + ent.hitbox[1]];
|
||||
|
||||
//if the hitboxes actually overlap
|
||||
if (!(hpos1[0] > hpos2[0]+ent.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
||||
if (!(hpos1[1] > hpos2[1]+ent.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
||||
if (ent instanceof Mario.Player) { //if we hit the player
|
||||
if (ent.vel[1] > 0) { //then the goomba dies
|
||||
this.stomp();
|
||||
} else if (ent.starTime) {
|
||||
this.bump();
|
||||
} else { //or the player gets hit
|
||||
ent.damage();
|
||||
}
|
||||
} else {
|
||||
this.collideWall();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Goomba.prototype.stomp = function() {
|
||||
sounds.stomp.play();
|
||||
player.bounce = true;
|
||||
this.sprite.pos[0] = 32;
|
||||
this.sprite.speed = 0;
|
||||
this.vel[0] = 0;
|
||||
this.dying = 10;
|
||||
};
|
||||
|
||||
Goomba.prototype.bump = function() {
|
||||
sounds.kick.play();
|
||||
this.sprite.img = 'sprites/enemyr.png';
|
||||
this.flipping = true;
|
||||
this.pos[1] -= 1;
|
||||
this.vel[0] = 0;
|
||||
this.vel[1] = -2.5;
|
||||
};
|
||||
})();
|
||||
@@ -1,54 +0,0 @@
|
||||
(function() {
|
||||
var pressedKeys = {};
|
||||
|
||||
function setKey(event, status) {
|
||||
var code = event.keyCode;
|
||||
var key;
|
||||
|
||||
switch(code) {
|
||||
case 32:
|
||||
key = 'SPACE'; break;
|
||||
case 37:
|
||||
key = 'LEFT'; break;
|
||||
case 38:
|
||||
key = 'UP'; break;
|
||||
case 39:
|
||||
key = 'RIGHT'; break;
|
||||
case 40:
|
||||
key = 'DOWN'; break;
|
||||
case 88:
|
||||
key = 'JUMP'; break;
|
||||
case 90:
|
||||
key = 'RUN'; break;
|
||||
default:
|
||||
key = String.fromCharCode(code);
|
||||
}
|
||||
|
||||
pressedKeys[key] = status;
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', function(e) {
|
||||
setKey(e, true);
|
||||
});
|
||||
|
||||
document.addEventListener('keyup', function(e) {
|
||||
setKey(e, false);
|
||||
});
|
||||
|
||||
window.addEventListener('blur', function() {
|
||||
pressedKeys = {};
|
||||
});
|
||||
|
||||
window.input = {
|
||||
isDown: function(key) {
|
||||
return pressedKeys[key.toUpperCase()];
|
||||
},
|
||||
reset: function() {
|
||||
pressedKeys['RUN'] = false;
|
||||
pressedKeys['LEFT'] = false;
|
||||
pressedKeys['RIGHT'] = false;
|
||||
pressedKeys['DOWN'] = false;
|
||||
pressedKeys['JUMP'] = false;
|
||||
}
|
||||
};
|
||||
})();
|
||||
@@ -1,211 +0,0 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
|
||||
var Koopa = Mario.Koopa = function(pos, sprite, para) {
|
||||
this.dying = false;
|
||||
this.shell = false;
|
||||
|
||||
this.para = para; //para. As in, is it a paratroopa?
|
||||
|
||||
//So, funny story. The actual hitboxes don't reach all the way to the ground.
|
||||
//What that means is, as long as I use them to keep things on the floor
|
||||
//making the hitboxes accurate will make enemies sink into the ground.
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: sprite,
|
||||
hitbox: [2,8,12,24]
|
||||
});
|
||||
this.vel[0] = -0.5;
|
||||
this.idx = level.enemies.length;
|
||||
};
|
||||
|
||||
Koopa.prototype.render = function(ctx, vX, vY) {
|
||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
};
|
||||
|
||||
Koopa.prototype.update = function(dt, vX) {
|
||||
if (this.turn) {
|
||||
this.vel[0] = -this.vel[0];
|
||||
if (this.shell) sounds.bump.play();
|
||||
this.turn = false;
|
||||
}
|
||||
if (this.vel[0] != 0) {
|
||||
this.left = (this.vel[0] < 0);
|
||||
}
|
||||
|
||||
if (this.left) {
|
||||
this.sprite.img = 'sprites/enemy.png';
|
||||
} else {
|
||||
this.sprite.img = 'sprites/enemyr.png';
|
||||
}
|
||||
|
||||
if (this.pos[0] - vX > 336) { //if we're too far away, do nothing.
|
||||
return;
|
||||
} else if (this.pos[0] - vX < -32) {
|
||||
delete level.enemies[this.idx];
|
||||
}
|
||||
|
||||
if (this.dying) {
|
||||
this.dying -= 1;
|
||||
if (!this.dying) {
|
||||
delete level.enemies[this.idx];
|
||||
}
|
||||
}
|
||||
|
||||
if (this.shell) {
|
||||
if (this.vel[0] == 0) {
|
||||
this.shell -= 1;
|
||||
if (this.shell < 120) {
|
||||
this.sprite.speed = 5;
|
||||
}
|
||||
if (this.shell == 0) {
|
||||
this.sprite = level.koopaSprite();
|
||||
this.hitbox = [2,8,12,24]
|
||||
if (this.left) {
|
||||
this.sprite.img = 'sprites/enemyr.png';
|
||||
this.vel[0] = 0.5;
|
||||
this.left = false;
|
||||
} else {
|
||||
this.vel[0] = -0.5;
|
||||
this.left = true;
|
||||
}
|
||||
this.pos[1] -= 16;
|
||||
}
|
||||
} else {
|
||||
this.shell = 360;
|
||||
this.sprite.speed = 0;
|
||||
this.sprite.setFrame(0);
|
||||
}
|
||||
}
|
||||
this.acc[1] = 0.2;
|
||||
this.vel[1] += this.acc[1];
|
||||
this.pos[0] += this.vel[0];
|
||||
this.pos[1] += this.vel[1];
|
||||
this.sprite.update(dt);
|
||||
};
|
||||
|
||||
Koopa.prototype.collideWall = function() {
|
||||
//This stops us from flipping twice on the same frame if we collide
|
||||
//with multiple wall tiles simultaneously.
|
||||
this.turn = true;
|
||||
};
|
||||
|
||||
Koopa.prototype.checkCollisions = function() {
|
||||
var h = this.shell ? 1 : 2;
|
||||
if (this.pos[1] % 16 !== 0) {
|
||||
h += 1;
|
||||
}
|
||||
var w = this.pos[0] % 16 === 0 ? 1 : 2;
|
||||
|
||||
var baseX = Math.floor(this.pos[0] / 16);
|
||||
var baseY = Math.floor(this.pos[1] / 16);
|
||||
|
||||
if (baseY + h > 15) {
|
||||
delete level.enemies[this.idx];
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.flipping) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < h; i++) {
|
||||
for (var j = 0; j < w; j++) {
|
||||
if (level.statics[baseY + i][baseX + j]) {
|
||||
level.statics[baseY + i][baseX + j].isCollideWith(this);
|
||||
}
|
||||
if (level.blocks[baseY + i][baseX + j]) {
|
||||
level.blocks[baseY + i][baseX + j].isCollideWith(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
var that = this;
|
||||
level.enemies.forEach(function(enemy){
|
||||
if (enemy === that) { //don't check collisions with ourselves.
|
||||
return;
|
||||
} else if (enemy.pos[0] - vX > 336){ //stop checking once we get to far away dudes.
|
||||
return;
|
||||
} else {
|
||||
that.isCollideWith(enemy);
|
||||
}
|
||||
});
|
||||
this.isCollideWith(player);
|
||||
};
|
||||
|
||||
Koopa.prototype.isCollideWith = function(ent) {
|
||||
if (ent instanceof Mario.Player && (this.dying || ent.invincibility)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
||||
var hpos1 = [this.pos[0] + this.hitbox[0], this.pos[1] + this.hitbox[1]];
|
||||
var hpos2 = [ent.pos[0] + ent.hitbox[0], ent.pos[1] + ent.hitbox[1]];
|
||||
|
||||
//if the hitboxes actually overlap
|
||||
if (!(hpos1[0] > hpos2[0]+ent.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
||||
if (!(hpos1[1] > hpos2[1]+ent.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
||||
if (ent instanceof Mario.Player) {
|
||||
if (ent.vel[1] > 0) {
|
||||
player.bounce = true;
|
||||
}
|
||||
if (this.shell) {
|
||||
sounds.kick.play();
|
||||
if (this.vel[0] === 0) {
|
||||
if (ent.left) { //I'm pretty sure this isn't the real logic.
|
||||
this.vel[0] = -4;
|
||||
} else {
|
||||
this.vel[0] = 4;
|
||||
}
|
||||
} else {
|
||||
if (ent.bounce) {
|
||||
this.vel[0] = 0;
|
||||
} else ent.damage();
|
||||
}
|
||||
} else if (ent.vel[1] > 0) { //then we get BOPPED.
|
||||
this.stomp();
|
||||
} else { //or the player gets hit
|
||||
ent.damage();
|
||||
}
|
||||
} else {
|
||||
if (this.shell && (ent instanceof Mario.Goomba)) {
|
||||
ent.bump();
|
||||
} else this.collideWall();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Koopa.prototype.stomp = function() {
|
||||
//Turn this thing into a shell if it isn't already. Kick it if it is.
|
||||
player.bounce = true;
|
||||
if (this.para) {
|
||||
this.para = false;
|
||||
this.sprite.pos[0] -= 32;
|
||||
} else {
|
||||
sounds.stomp.play();
|
||||
this.shell = 360;
|
||||
this.sprite.pos[0] += 64;
|
||||
this.sprite.pos[1] += 16;
|
||||
this.sprite.size = [16,16];
|
||||
this.hitbox = [2,0,12,16];
|
||||
this.sprite.speed = 0;
|
||||
this.frames = [0,1];
|
||||
this.vel = [0,0];
|
||||
this.pos[1] += 16;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Koopa.prototype.bump = function() {
|
||||
sounds.kick.play();
|
||||
if (this.flipping) return;
|
||||
this.flipping = true;
|
||||
this.sprite.pos = [160, 0];
|
||||
this.sprite.size = [16,16];
|
||||
this.hitbox = [2, 0, 12, 16];
|
||||
this.sprite.speed = 0;
|
||||
this.vel[0] = 0;
|
||||
this.vel[1] = -2.5;
|
||||
};
|
||||
})();
|
||||
@@ -1,219 +0,0 @@
|
||||
var oneone = Mario.oneone = function() {
|
||||
//The things that need to be passed in are basically just dependent on what
|
||||
//tileset we're in, so it makes more sense to just make one variable for that, so
|
||||
//TODO: put as much of this in the Level object definition as possible.
|
||||
level = new Mario.Level({
|
||||
playerPos: [56,192],
|
||||
loader: Mario.oneone,
|
||||
background: "#7974FF",
|
||||
scrolling: true,
|
||||
invincibility: [144, 192, 240],
|
||||
exit: 204,
|
||||
floorSprite: new Mario.Sprite('sprites/tiles.png', [0,0],[16,16],0),
|
||||
cloudSprite: new Mario.Sprite('sprites/tiles.png', [0,320],[48,32],0),
|
||||
wallSprite: new Mario.Sprite('sprites/tiles.png', [0, 16],[16,16],0),
|
||||
brickSprite: new Mario.Sprite('sprites/tiles.png', [16, 0], [16,16], 0),
|
||||
brickBounceSprite: new Mario.Sprite('sprites/tiles.png',[32,0],[16,16],0),
|
||||
rubbleSprite: function () {
|
||||
return new Mario.Sprite('sprites/items.png', [64,0], [8,8], 3, [0,1])
|
||||
},
|
||||
ublockSprite: new Mario.Sprite('sprites/tiles.png', [48, 0], [16,16],0),
|
||||
superShroomSprite: new Mario.Sprite('sprites/items.png', [0,0], [16,16], 0),
|
||||
fireFlowerSprite: new Mario.Sprite('sprites/items.png', [0,32], [16,16], 20, [0,1,2,3]),
|
||||
starSprite: new Mario.Sprite('sprites/items.png', [0,48], [16,16], 20, [0,1,2,3]),
|
||||
pipeLEndSprite: new Mario.Sprite('sprites/tiles.png', [0, 128], [16,16], 0),
|
||||
pipeREndSprite: new Mario.Sprite('sprites/tiles.png', [16, 128], [16,16], 0),
|
||||
pipeLMidSprite: new Mario.Sprite('sprites/tiles.png', [0, 144], [16,16], 0),
|
||||
pipeRMidSprite: new Mario.Sprite('sprites/tiles.png', [16, 144], [16,16], 0),
|
||||
|
||||
pipeUpMid: new Mario.Sprite('sprites/tiles.png', [0, 144], [32,16], 0),
|
||||
pipeSideMid: new Mario.Sprite('sprites/tiles.png', [48, 128], [16,32], 0),
|
||||
pipeLeft: new Mario.Sprite('sprites/tiles.png', [32, 128], [16,32], 0),
|
||||
pipeTop: new Mario.Sprite('sprites/tiles.png', [0, 128], [32,16], 0),
|
||||
qblockSprite: new Mario.Sprite('sprites/tiles.png', [384, 0], [16,16], 8, [0,0,0,0,1,2,1]),
|
||||
bcoinSprite: function() {
|
||||
return new Mario.Sprite('sprites/items.png', [0,112],[16,16], 20,[0,1,2,3]);
|
||||
},
|
||||
cloudSprites:[
|
||||
new Mario.Sprite('sprites/tiles.png', [0,320],[16,32],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [16,320],[16,32],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [32,320],[16,32],0)
|
||||
],
|
||||
hillSprites: [
|
||||
new Mario.Sprite('sprites/tiles.png', [128,128],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [144,128],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [160,128],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [128,144],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [144,144],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [160,144],[16,16],0)
|
||||
],
|
||||
bushSprite: new Mario.Sprite('sprites/tiles.png', [176, 144], [48, 16], 0),
|
||||
bushSprites: [
|
||||
new Mario.Sprite('sprites/tiles.png', [176,144], [16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [192,144], [16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [208,144], [16,16],0)],
|
||||
goombaSprite: function() {
|
||||
return new Mario.Sprite('sprites/enemy.png', [0, 16], [16,16], 3, [0,1]);
|
||||
},
|
||||
koopaSprite: function() {
|
||||
return new Mario.Sprite('sprites/enemy.png', [96,0], [16,32], 2, [0,1]);
|
||||
},
|
||||
flagPoleSprites: [
|
||||
new Mario.Sprite('sprites/tiles.png', [256, 128], [16,16], 0),
|
||||
new Mario.Sprite('sprites/tiles.png', [256, 144], [16,16], 0),
|
||||
new Mario.Sprite('sprites/items.png', [128, 32], [16,16], 0)
|
||||
]
|
||||
});
|
||||
ground = [[0,69],[71,86],[89,153],[155,212]];
|
||||
player.pos[0] = level.playerPos[0];
|
||||
player.pos[1] = level.playerPos[1];
|
||||
vX = 0;
|
||||
|
||||
//build THE GROUND
|
||||
ground.forEach(function(loc) {
|
||||
level.putFloor(loc[0],loc[1]);
|
||||
});
|
||||
|
||||
//build scenery
|
||||
clouds = [[7,3],[19, 2],[56, 3],[67, 2],[87, 2],[103, 2],[152, 3],[163, 2],[200, 3]];
|
||||
clouds.forEach(function(cloud){
|
||||
level.putCloud(cloud[0],cloud[1]);
|
||||
});
|
||||
|
||||
twoClouds = [[36,2],[132,2],[180,2]];
|
||||
twoClouds.forEach(function(cloud){
|
||||
level.putTwoCloud(cloud[0],cloud[1]);
|
||||
});
|
||||
|
||||
threeClouds = [[27,3],[75,3],[123,3],[171,3]];
|
||||
threeClouds.forEach(function(cloud){
|
||||
level.putThreeCloud(cloud[0],cloud[1]);
|
||||
});
|
||||
|
||||
bHills = [0,48,96,144,192]
|
||||
bHills.forEach(function(hill) {
|
||||
level.putBigHill(hill, 12);
|
||||
});
|
||||
|
||||
sHills = [16,64,111,160];
|
||||
sHills.forEach(function(hill) {
|
||||
level.putSmallHill(hill, 12);
|
||||
});
|
||||
|
||||
bushes = [23,71,118,167];
|
||||
bushes.forEach(function(bush) {
|
||||
level.putBush(bush, 12);
|
||||
});
|
||||
|
||||
twoBushes = [41,89,137];
|
||||
twoBushes.forEach(function(bush) {
|
||||
level.putTwoBush(bush, 12);
|
||||
});
|
||||
|
||||
threeBushes = [11,59,106];
|
||||
threeBushes.forEach(function(bush) {
|
||||
level.putThreeBush(bush, 12);
|
||||
});
|
||||
|
||||
//interactable terrain
|
||||
level.putQBlock(16, 9, new Mario.Bcoin([256, 144]));
|
||||
level.putBrick(20, 9, null);
|
||||
level.putQBlock(21, 9, new Mario.Mushroom([336, 144]));
|
||||
level.putBrick(22, 9, null);
|
||||
level.putQBlock(22, 5, new Mario.Bcoin([352, 80]));
|
||||
level.putQBlock(23, 9, new Mario.Bcoin([368, 144]));
|
||||
level.putBrick(24, 9, null);
|
||||
level.putPipe(28, 13, 2);
|
||||
level.putPipe(38, 13, 3);
|
||||
level.putPipe(46, 13, 4);
|
||||
level.putRealPipe(57, 9, 4, "DOWN", Mario.oneonetunnel);
|
||||
level.putBrick(77, 9, null);
|
||||
level.putQBlock(78, 9, new Mario.Mushroom([1248, 144]));
|
||||
level.putBrick(79, 9, null);
|
||||
level.putBrick(80, 5, null);
|
||||
level.putBrick(81, 5, null);
|
||||
level.putBrick(82, 5, null);
|
||||
level.putBrick(83, 5, null);
|
||||
level.putBrick(84, 5, null);
|
||||
level.putBrick(85, 5, null);
|
||||
level.putBrick(86, 5, null);
|
||||
level.putBrick(87, 5, null);
|
||||
level.putBrick(91, 5, null);
|
||||
level.putBrick(92, 5, null);
|
||||
level.putBrick(93, 5, null);
|
||||
level.putQBlock(94, 5, new Mario.Bcoin([1504, 80]));
|
||||
level.putBrick(94, 9, null);
|
||||
level.putBrick(100, 9, new Mario.Star([1600, 144]));
|
||||
level.putBrick(101, 9, null);
|
||||
level.putQBlock(105, 9, new Mario.Bcoin([1680, 144]));
|
||||
level.putQBlock(108, 9, new Mario.Bcoin([1728, 144]));
|
||||
level.putQBlock(108, 5, new Mario.Mushroom([1728, 80]));
|
||||
level.putQBlock(111, 9, new Mario.Bcoin([1776, 144]));
|
||||
level.putBrick(117, 9, null);
|
||||
level.putBrick(120, 5, null);
|
||||
level.putBrick(121, 5, null);
|
||||
level.putBrick(122, 5, null);
|
||||
level.putBrick(123, 5, null);
|
||||
level.putBrick(128, 5, null);
|
||||
level.putQBlock(129, 5, new Mario.Bcoin([2074, 80]));
|
||||
level.putBrick(129, 9, null);
|
||||
level.putQBlock(130, 5, new Mario.Bcoin([2080, 80]));
|
||||
level.putBrick(130, 9, null);
|
||||
level.putBrick(131, 5, null);
|
||||
level.putWall(134, 13, 1);
|
||||
level.putWall(135, 13, 2);
|
||||
level.putWall(136, 13, 3);
|
||||
level.putWall(137, 13, 4);
|
||||
level.putWall(140, 13, 4);
|
||||
level.putWall(141, 13, 3);
|
||||
level.putWall(142, 13, 2);
|
||||
level.putWall(143, 13, 1);
|
||||
level.putWall(148, 13, 1);
|
||||
level.putWall(149, 13, 2);
|
||||
level.putWall(150, 13, 3);
|
||||
level.putWall(151, 13, 4);
|
||||
level.putWall(152, 13, 4);
|
||||
level.putWall(155, 13, 4);
|
||||
level.putWall(156, 13, 3);
|
||||
level.putWall(157, 13, 2);
|
||||
level.putWall(158, 13, 1);
|
||||
level.putPipe(163, 13, 2);
|
||||
level.putBrick(168, 9, null);
|
||||
level.putBrick(169, 9, null);
|
||||
level.putQBlock(170, 9, new Mario.Bcoin([2720, 144]));
|
||||
level.putBrick(171, 9, null);
|
||||
level.putPipe(179, 13, 2);
|
||||
level.putWall(181, 13, 1);
|
||||
level.putWall(182, 13, 2);
|
||||
level.putWall(183, 13, 3);
|
||||
level.putWall(184, 13, 4);
|
||||
level.putWall(185, 13, 5);
|
||||
level.putWall(186, 13, 6);
|
||||
level.putWall(187, 13, 7);
|
||||
level.putWall(188, 13, 8);
|
||||
level.putWall(189, 13, 8);
|
||||
level.putFlagpole(198);
|
||||
|
||||
//and enemies
|
||||
level.putGoomba(22, 12);
|
||||
level.putGoomba(40, 12);
|
||||
level.putGoomba(50, 12);
|
||||
level.putGoomba(51, 12);
|
||||
level.putGoomba(82, 4);
|
||||
level.putGoomba(84, 4);
|
||||
level.putGoomba(100, 12);
|
||||
level.putGoomba(102, 12);
|
||||
level.putGoomba(114, 12);
|
||||
level.putGoomba(115, 12);
|
||||
level.putGoomba(122, 12);
|
||||
level.putGoomba(123, 12);
|
||||
level.putGoomba(125, 12);
|
||||
level.putGoomba(126, 12);
|
||||
level.putGoomba(170, 12);
|
||||
level.putGoomba(172, 12);
|
||||
level.putKoopa(35, 11);
|
||||
|
||||
music.underground.pause();
|
||||
// music.overworld.currentTime = 0;
|
||||
music.overworld.play();
|
||||
};
|
||||
@@ -1,65 +0,0 @@
|
||||
var oneonetunnel = Mario.oneonetunnel = function() {
|
||||
level = new Mario.Level({
|
||||
playerPos: [40,16],
|
||||
loader: Mario.oneonetunnel,
|
||||
background: "#000000",
|
||||
scrolling: false,
|
||||
coinSprite: function() {
|
||||
return new Mario.Sprite('sprites/items.png', [0,96],[16,16], 6,[0,0,0,0,1,2,1]);
|
||||
},
|
||||
floorSprite: new Mario.Sprite('sprites/tiles.png', [0,32],[16,16],0),
|
||||
wallSprite: new Mario.Sprite('sprites/tiles.png', [32, 32],[16,16],0),
|
||||
brickSprite: new Mario.Sprite('sprites/tiles.png', [16, 0], [16,16], 0),
|
||||
brickBounceSprite: new Mario.Sprite('sprites/tiles.png',[32,0],[16,16],0),
|
||||
ublockSprite: new Mario.Sprite('sprites/tiles.png', [48, 0], [16,16],0),
|
||||
pipeLMidSprite: new Mario.Sprite('sprites/tiles.png', [0, 144], [16,16], 0),
|
||||
pipeRMidSprite: new Mario.Sprite('sprites/tiles.png', [16, 144], [16,16], 0),
|
||||
pipeLEndSprite: new Mario.Sprite('sprites/tiles.png', [0, 128], [16,16], 0),
|
||||
pipeREndSprite: new Mario.Sprite('sprites/tiles.png', [16, 128], [16,16], 0),
|
||||
pipeUpMid: new Mario.Sprite('sprites/tiles.png', [0, 144], [32,16], 0),
|
||||
pipeSideMid: new Mario.Sprite('sprites/tiles.png', [48, 128], [16,32], 0),
|
||||
pipeLeft: new Mario.Sprite('sprites/tiles.png', [32, 128], [16,32], 0),
|
||||
pipeTop: new Mario.Sprite('sprites/tiles.png', [0, 128], [32,16], 0),
|
||||
|
||||
LPipeSprites:[
|
||||
new Mario.Sprite('sprites/tiles.png', [32,128],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [32,144],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [48,128],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [48,144],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [64,128],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [64,144],[16,16],0),
|
||||
]
|
||||
|
||||
});
|
||||
|
||||
player.pos[0] = level.playerPos[0];
|
||||
player.pos[1] = level.playerPos[1];
|
||||
vX = 0;
|
||||
level.putFloor(0,16);
|
||||
level.putWall(0,13,11);
|
||||
walls = [4,5,6,7,8,9,10];
|
||||
walls.forEach(function(loc){
|
||||
level.putWall(loc,13,3);
|
||||
level.putWall(loc,3,1);
|
||||
});
|
||||
|
||||
coins = [[5,5], [6,5], [7,5], [8,5], [9,5],
|
||||
[4,7], [5,7], [6,7], [7,7], [8,7], [9,7], [10,7],
|
||||
[4,9], [5,9], [6,9], [7,9], [8,9], [9,9], [10,9]];
|
||||
coins.forEach(function(pos){
|
||||
level.putCoin(pos[0],pos[1]);
|
||||
});
|
||||
|
||||
//level.putLeftPipe(13,11);
|
||||
level.putRealPipe(13,11,3,"RIGHT", function() {
|
||||
Mario.oneone.call();
|
||||
player.pos = [2616, 177]
|
||||
player.pipe("UP", function() {;});
|
||||
});
|
||||
|
||||
level.putPipe(15,13,13);
|
||||
|
||||
music.overworld.pause();
|
||||
music.underground.currentTime = 0;
|
||||
music.underground.play();
|
||||
};
|
||||
@@ -1,218 +0,0 @@
|
||||
(function() {
|
||||
var Level = Mario.Level = function(options) {
|
||||
this.playerPos = options.playerPos;
|
||||
this.scrolling = options.scrolling;
|
||||
this.loader = options.loader;
|
||||
this.background = options.background;
|
||||
this.exit = options.exit;
|
||||
|
||||
this.floorSprite = options.floorSprite;
|
||||
this.cloudSprite = options.cloudSprite;
|
||||
this.wallSprite = options.wallSprite;
|
||||
this.brickSprite = options.brickSprite;
|
||||
this.rubbleSprite = options.rubbleSprite;
|
||||
this.brickBounceSprite = options.brickBounceSprite;
|
||||
this.ublockSprite = options.ublockSprite;
|
||||
this.superShroomSprite = options.superShroomSprite;
|
||||
this.fireFlowerSprite = options.fireFlowerSprite;
|
||||
this.starSprite = options.starSprite;
|
||||
this.coinSprite = options.coinSprite;
|
||||
this.bcoinSprite = options.bcoinSprite;
|
||||
this.goombaSprite = options.goombaSprite;
|
||||
this.koopaSprite = options.koopaSprite;
|
||||
|
||||
//prop pipe sprites, to be phased out
|
||||
this.pipeLEndSprite = options.pipeLEndSprite;
|
||||
this.pipeREndSprite = options.pipeREndSprite;
|
||||
this.pipeLMidSprite = options.pipeLMidSprite;
|
||||
this.pipeRMidSprite = options.pipeRMidSprite;
|
||||
|
||||
//real pipe sprites, use these.
|
||||
this.pipeUpMid = options.pipeUpMid;
|
||||
this.pipeSideMid = options.pipeSideMid;
|
||||
this.pipeLeft = options.pipeLeft;
|
||||
this.pipeTop = options.pipeTop;
|
||||
|
||||
this.flagpoleSprites = options.flagPoleSprites;
|
||||
|
||||
this.LPipeSprites = options.LPipeSprites;
|
||||
this.cloudSprites = options.cloudSprites;
|
||||
this.hillSprites = options.hillSprites;
|
||||
this.bushSprite = options.bushSprite;
|
||||
this.bushSprites = options.bushSprites;
|
||||
this.qblockSprite = options.qblockSprite;
|
||||
|
||||
this.invincibility = options.invincibility;
|
||||
this.statics = [];
|
||||
this.scenery = [];
|
||||
this.blocks = [];
|
||||
this.enemies = [];
|
||||
this.items = [];
|
||||
this.pipes = [];
|
||||
|
||||
for (var i = 0; i < 15; i++) {
|
||||
this.statics[i] = [];
|
||||
this.scenery[i] = [];
|
||||
this.blocks[i] = [];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Level.prototype.putFloor = function(start, end) {
|
||||
for (var i = start; i < end; i++) {
|
||||
this.statics[13][i] = new Mario.Floor([16*i,208], this.floorSprite);
|
||||
this.statics[14][i] = new Mario.Floor([16*i,224], this.floorSprite);
|
||||
}
|
||||
};
|
||||
|
||||
Level.prototype.putGoomba = function(x, y) {
|
||||
this.enemies.push(new Mario.Goomba([16*x, 16*y], this.goombaSprite() ));
|
||||
};
|
||||
|
||||
Level.prototype.putKoopa = function(x, y) {
|
||||
this.enemies.push(new Mario.Koopa([16*x, 16*y], this.koopaSprite(), false));
|
||||
};
|
||||
|
||||
Level.prototype.putWall = function(x, y, height) {
|
||||
//y is the bottom of the wall in this case.
|
||||
for (var i = y-height; i < y; i++) {
|
||||
this.statics[i][x] = new Mario.Floor([16*x, 16*i], this.wallSprite);
|
||||
}
|
||||
};
|
||||
|
||||
Level.prototype.putPipe = function(x, y, height) {
|
||||
for (var i = y - height; i < y; i++) {
|
||||
if (i === y - height) {
|
||||
this.statics[i][x] = new Mario.Floor([16*x, 16*i], this.pipeLEndSprite);
|
||||
this.statics[i][x+1] = new Mario.Floor([16*x+16, 16*i], this.pipeREndSprite);
|
||||
} else {
|
||||
this.statics[i][x] = new Mario.Floor([16*x, 16*i], this.pipeLMidSprite);
|
||||
this.statics[i][x+1] = new Mario.Floor([16*x+16, 16*i], this.pipeRMidSprite);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//sometimes, pipes don't go straight up and down.
|
||||
Level.prototype.putLeftPipe = function(x,y) {
|
||||
this.statics[y][x] = new Mario.Floor([16*x, 16*y], this.LPipeSprites[0]);
|
||||
this.statics[y+1][x] = new Mario.Floor([16*x,16*(y+1)], this.LPipeSprites[1]);
|
||||
this.statics[y][x+1] = new Mario.Floor([16*(x+1),16*y], this.LPipeSprites[2]);
|
||||
this.statics[y+1][x+1] = new Mario.Floor([16*(x+1),16*(y+1)], this.LPipeSprites[3]);
|
||||
this.statics[y][x+2] = new Mario.Floor([16*(x+2),16*y], this.LPipeSprites[4]);
|
||||
this.statics[y+1][x+2] = new Mario.Floor([16*(x+2),16*(y+1)], this.LPipeSprites[5]);
|
||||
};
|
||||
|
||||
Level.prototype.putCoin = function(x, y) {
|
||||
this.items.push(new Mario.Coin(
|
||||
[x*16, y*16],
|
||||
this.coinSprite()
|
||||
));
|
||||
};
|
||||
|
||||
Level.prototype.putCloud = function(x, y) {
|
||||
this.scenery[y][x] = new Mario.Prop([x*16, y*16], this.cloudSprite);
|
||||
};
|
||||
|
||||
Level.prototype.putQBlock = function(x, y, item) {
|
||||
this.blocks[y][x] = new Mario.Block( {
|
||||
pos: [x*16, y*16],
|
||||
item: item,
|
||||
sprite: this.qblockSprite,
|
||||
usedSprite: this.ublockSprite
|
||||
});
|
||||
};
|
||||
|
||||
Level.prototype.putBrick = function(x,y,item) {
|
||||
this.blocks[y][x] = new Mario.Block({
|
||||
pos: [x*16, y*16],
|
||||
item: item,
|
||||
sprite: this.brickSprite,
|
||||
bounceSprite: this.brickBounceSprite,
|
||||
usedSprite: this.ublockSprite,
|
||||
breakable: !item
|
||||
});
|
||||
};
|
||||
|
||||
Level.prototype.putBigHill = function(x, y) {
|
||||
var px = x*16, py = y*16;
|
||||
this.scenery[y][x] = new Mario.Prop([px, py], this.hillSprites[0]);
|
||||
this.scenery[y][x+1] = new Mario.Prop([px+16, py], this.hillSprites[3]);
|
||||
this.scenery[y-1][x+1] = new Mario.Prop([px+16, py-16], this.hillSprites[0]);
|
||||
this.scenery[y][x+2] = new Mario.Prop([px+32, py], this.hillSprites[4]);
|
||||
this.scenery[y-1][x+2] = new Mario.Prop([px+32, py-16], this.hillSprites[3]);
|
||||
this.scenery[y-2][x+2] = new Mario.Prop([px+32, py-32], this.hillSprites[1]);
|
||||
this.scenery[y][x+3] = new Mario.Prop([px+48, py], this.hillSprites[5]);
|
||||
this.scenery[y-1][x+3] = new Mario.Prop([px+48, py-16], this.hillSprites[2]);
|
||||
this.scenery[y][x+4] = new Mario.Prop([px+64, py], this.hillSprites[2]);
|
||||
};
|
||||
|
||||
Level.prototype.putBush = function(x, y) {
|
||||
this.scenery[y][x] = new Mario.Prop([x*16, y*16], this.bushSprite);
|
||||
};
|
||||
|
||||
Level.prototype.putThreeBush = function(x,y) {
|
||||
px = x*16;
|
||||
py = y*16;
|
||||
this.scenery[y][x] = new Mario.Prop([px, py], this.bushSprites[0]);
|
||||
this.scenery[y][x+1] = new Mario.Prop([px+16, py], this.bushSprites[1]);
|
||||
this.scenery[y][x+2] = new Mario.Prop([px+32, py], this.bushSprites[1]);
|
||||
this.scenery[y][x+3] = new Mario.Prop([px+48, py], this.bushSprites[1]);
|
||||
this.scenery[y][x+4] = new Mario.Prop([px+64, py], this.bushSprites[2]);
|
||||
};
|
||||
|
||||
Level.prototype.putTwoBush = function(x,y) {
|
||||
px = x*16;
|
||||
py = y*16;
|
||||
this.scenery[y][x] = new Mario.Prop([px, py], this.bushSprites[0]);
|
||||
this.scenery[y][x+1] = new Mario.Prop([px+16, py], this.bushSprites[1]);
|
||||
this.scenery[y][x+2] = new Mario.Prop([px+32, py], this.bushSprites[1]);
|
||||
this.scenery[y][x+3] = new Mario.Prop([px+48, py], this.bushSprites[2]);
|
||||
};
|
||||
|
||||
Level.prototype.putSmallHill = function(x, y) {
|
||||
var px = x*16, py = y*16;
|
||||
this.scenery[y][x] = new Mario.Prop([px, py], this.hillSprites[0]);
|
||||
this.scenery[y][x+1] = new Mario.Prop([px+16, py], this.hillSprites[3]);
|
||||
this.scenery[y-1][x+1] = new Mario.Prop([px+16, py-16], this.hillSprites[1]);
|
||||
this.scenery[y][x+2] = new Mario.Prop([px+32, py], this.hillSprites[2]);
|
||||
};
|
||||
|
||||
Level.prototype.putTwoCloud = function(x,y) {
|
||||
px = x*16;
|
||||
py = y*16;
|
||||
this.scenery[y][x] = new Mario.Prop([px, py], this.cloudSprites[0]);
|
||||
this.scenery[y][x+1] = new Mario.Prop([px+16, py], this.cloudSprites[1]);
|
||||
this.scenery[y][x+2] = new Mario.Prop([px+32, py], this.cloudSprites[1]);
|
||||
this.scenery[y][x+3] = new Mario.Prop([px+48, py], this.cloudSprites[2]);
|
||||
};
|
||||
|
||||
Level.prototype.putThreeCloud = function(x,y) {
|
||||
px = x*16;
|
||||
py = y*16;
|
||||
this.scenery[y][x] = new Mario.Prop([px, py], this.cloudSprites[0]);
|
||||
this.scenery[y][x+1] = new Mario.Prop([px+16, py], this.cloudSprites[1]);
|
||||
this.scenery[y][x+2] = new Mario.Prop([px+32, py], this.cloudSprites[1]);
|
||||
this.scenery[y][x+3] = new Mario.Prop([px+48, py], this.cloudSprites[1]);
|
||||
this.scenery[y][x+4] = new Mario.Prop([px+64, py], this.cloudSprites[2]);
|
||||
};
|
||||
|
||||
Level.prototype.putRealPipe = function(x, y, length, direction, destination) {
|
||||
px = x*16;
|
||||
py = y*16;
|
||||
this.pipes.push(new Mario.Pipe({
|
||||
pos: [px, py],
|
||||
length: length,
|
||||
direction: direction,
|
||||
destination: destination
|
||||
}));
|
||||
}
|
||||
|
||||
Level.prototype.putFlagpole = function(x) {
|
||||
this.statics[12][x] = new Mario.Floor([16*x, 192], this.wallSprite);
|
||||
for (i=3; i < 12; i++) {
|
||||
this.scenery[i][x] = new Mario.Prop([16*x, 16*i], this.flagpoleSprites[1])
|
||||
}
|
||||
this.scenery[2][x] = new Mario.Prop([16*x, 32], this.flagpoleSprites[0]);
|
||||
this.items.push(new Mario.Flag(16*x));
|
||||
}
|
||||
})();
|
||||
@@ -1,118 +0,0 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
|
||||
var Mushroom = Mario.Mushroom = function(pos) {
|
||||
this.spawning = false;
|
||||
this.waiting = 0;
|
||||
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: level.superShroomSprite,
|
||||
hitbox: [0,0,16,16]
|
||||
});
|
||||
}
|
||||
|
||||
Mario.Util.inherits(Mushroom, Mario.Entity);
|
||||
|
||||
Mushroom.prototype.render = function(ctx, vX, vY) {
|
||||
if (this.spawning > 1) return;
|
||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
}
|
||||
|
||||
Mushroom.prototype.spawn = function() {
|
||||
if (player.power > 0) {
|
||||
//replace this with a fire flower
|
||||
var ff = new Mario.Fireflower(this.pos)
|
||||
ff.spawn();
|
||||
return;
|
||||
}
|
||||
sounds.itemAppear.play();
|
||||
this.idx = level.items.length;
|
||||
level.items.push(this);
|
||||
this.spawning = 12;
|
||||
this.targetpos = [];
|
||||
this.targetpos[0] = this.pos[0];
|
||||
this.targetpos[1] = this.pos[1] - 16;
|
||||
}
|
||||
|
||||
Mushroom.prototype.update = function(dt) {
|
||||
if (this.spawning > 1) {
|
||||
this.spawning -= 1;
|
||||
if (this.spawning == 1) this.vel[1] = -.5;
|
||||
return;
|
||||
}
|
||||
if (this.spawning) {
|
||||
if (this.pos[1] <= this.targetpos[1]) {
|
||||
this.pos[1] = this.targetpos[1];
|
||||
this.vel[1] = 0;
|
||||
this.waiting = 5;
|
||||
this.spawning = 0;
|
||||
this.vel[0] = 1;
|
||||
}
|
||||
} else {
|
||||
this.acc[1] = 0.2;
|
||||
}
|
||||
|
||||
if (this.waiting) {
|
||||
this.waiting -= 1;
|
||||
} else {
|
||||
this.vel[1] += this.acc[1];
|
||||
this.pos[0] += this.vel[0];
|
||||
this.pos[1] += this.vel[1];
|
||||
this.sprite.update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
Mushroom.prototype.collideWall = function() {
|
||||
this.vel[0] = -this.vel[0];
|
||||
}
|
||||
|
||||
Mushroom.prototype.checkCollisions = function() {
|
||||
if(this.spawning) {
|
||||
return;
|
||||
}
|
||||
var h = this.pos[1] % 16 == 0 ? 1 : 2;
|
||||
var w = this.pos[0] % 16 == 0 ? 1 : 2;
|
||||
|
||||
var baseX = Math.floor(this.pos[0] / 16);
|
||||
var baseY = Math.floor(this.pos[1] / 16);
|
||||
|
||||
if (baseY + h > 15) {
|
||||
delete level.items[this.idx];
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < h; i++) {
|
||||
for (var j = 0; j < w; j++) {
|
||||
if (level.statics[baseY + i][baseX + j]) {
|
||||
level.statics[baseY + i][baseX + j].isCollideWith(this);
|
||||
}
|
||||
if (level.blocks[baseY + i][baseX + j]) {
|
||||
level.blocks[baseY + i][baseX + j].isCollideWith(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.isPlayerCollided();
|
||||
}
|
||||
|
||||
//we have access to player everywhere, so let's just do this.
|
||||
Mushroom.prototype.isPlayerCollided = function() {
|
||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
||||
var hpos1 = [this.pos[0] + this.hitbox[0], this.pos[1] + this.hitbox[1]];
|
||||
var hpos2 = [player.pos[0] + player.hitbox[0], player.pos[1] + player.hitbox[1]];
|
||||
|
||||
//if the hitboxes actually overlap
|
||||
if (!(hpos1[0] > hpos2[0]+player.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
||||
if (!(hpos1[1] > hpos2[1]+player.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
||||
player.powerUp(this.idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mushroom.prototype.bump = function() {
|
||||
this.vel[1] = -2;
|
||||
}
|
||||
|
||||
})();
|
||||
@@ -1,45 +0,0 @@
|
||||
Enemy:
|
||||
#collideWith
|
||||
checks collision. Bounces off of walls and other enemies. Kills marios.
|
||||
gets killed by block bonk from below
|
||||
|
||||
Specific enemy behaviors:
|
||||
koopas get replaced with shells
|
||||
shells get kicked if touched from the side, instead of killing
|
||||
|
||||
Mario:
|
||||
#collideWith
|
||||
gets expelled from walls, bonks blocks, destroys blocks as big Mario
|
||||
note: collision with blocks is determined by which one is over the center
|
||||
if you're slightly to the side, you slip past it.
|
||||
Crazy-ass sprite shifting if you're in star mode!
|
||||
|
||||
|
||||
Item
|
||||
#collideWith
|
||||
item pickup logic
|
||||
|
||||
Mushroom
|
||||
#update
|
||||
movement logic for mushrooms
|
||||
get impulse from being block bonked
|
||||
this can be implemented by giving them the appropriate accel
|
||||
just if they overlap a block from the bottom.
|
||||
of course, only AFTER they finish sliding out of the block.
|
||||
|
||||
Water levels:
|
||||
make a separate class for water Marios
|
||||
less gravity
|
||||
swimming sprite
|
||||
fireballs are the same
|
||||
jump works when not on the ground
|
||||
different enemies
|
||||
|
||||
|
||||
TODO: Make level loader use hashes instead of arrays where possible.
|
||||
Should be a free performance gain.
|
||||
|
||||
Should also make item deletion less weird.
|
||||
|
||||
TODO: Make gravity exist higher up instead of having a magic number.
|
||||
Note from the future: Nope. Different objects have different gravity.
|
||||
@@ -1,160 +0,0 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
|
||||
|
||||
//there are too many possible configurations of pipe to capture in a reasonable
|
||||
//set of simple variables. Joints, etc. are just too much.
|
||||
//To that end, the pipe class handles simple pipes, and we'll put together
|
||||
//anything more complex with individual props. OK? OK.
|
||||
Pipe = Mario.Pipe = function(options) {
|
||||
this.pos = options.pos
|
||||
|
||||
//NOTE: direction is the direction you move INTO the pipe.
|
||||
this.direction = options.direction
|
||||
this.destination = options.destination
|
||||
this.length = options.length;
|
||||
|
||||
if (this.direction === "UP" || this.direction === "DOWN") {
|
||||
this.hitbox = [0,0, 32, this.length * 16];
|
||||
this.midsection = level.pipeUpMid;
|
||||
this.endsection = level.pipeTop;
|
||||
} else {
|
||||
this.hitbox = [0,0, 16*this.length, 32];
|
||||
this.midsection = level.pipeSideMid;
|
||||
this.endsection = level.pipeLeft;
|
||||
}
|
||||
}
|
||||
|
||||
Pipe.prototype.checkPipe = function() {
|
||||
if (this.destination === undefined || !input.isDown(this.direction)) return;
|
||||
|
||||
var h = player.power===0 ? 16 : 32;
|
||||
var x = Math.floor(player.pos[0]);
|
||||
var y = Math.floor(player.pos[1]);
|
||||
switch (this.direction) {
|
||||
case 'RIGHT': if (x === this.pos[0]-16 &&
|
||||
y >= this.pos[1] &&
|
||||
y+h <= this.pos[1]+32) {
|
||||
player.pipe(this.direction, this.destination)
|
||||
}
|
||||
break;
|
||||
case 'LEFT': if (x === this.pos[0]+16*this.length &&
|
||||
y >= this.pos[1] &&
|
||||
y+h <= this.pos[1]+32) {
|
||||
player.pipe(this.direction, this.destination)
|
||||
}
|
||||
break;
|
||||
case 'UP': if (y === this.pos[1] + 16*this.length &&
|
||||
x >= this.pos[0] &&
|
||||
x+16 <= this.pos[0]+32) {
|
||||
player.pipe(this.direction, this.destination)
|
||||
}
|
||||
break;
|
||||
case 'DOWN': if (y+h === this.pos[1] &&
|
||||
x >= this.pos[0] &&
|
||||
x+16 <= this.pos[0]+32) {
|
||||
player.pipe(this.direction, this.destination);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Note to self: next time, decide on a convention for which thing checks for collisions
|
||||
//and stick to it. This is a pain.
|
||||
Pipe.prototype.checkCollisions = function() {
|
||||
var that = this;
|
||||
level.enemies.forEach (function(ent) {
|
||||
that.isCollideWith(ent);
|
||||
});
|
||||
|
||||
level.items.forEach (function(ent) {
|
||||
that.isCollideWith(ent);
|
||||
});
|
||||
|
||||
fireballs.forEach(function(ent){
|
||||
that.isCollideWith(ent)
|
||||
});
|
||||
|
||||
if (!player.piping) this.isCollideWith(player);
|
||||
}
|
||||
|
||||
Pipe.prototype.isCollideWith = function (ent) {
|
||||
//long story short: because we scan every item, and and one 'rubble' item is four things with separate positions
|
||||
//we'll crash without this line as soon as we destroy a block. OOPS.
|
||||
if (ent.pos === undefined) return;
|
||||
|
||||
|
||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
||||
var hpos1 = [Math.floor(this.pos[0] + this.hitbox[0]), Math.floor(this.pos[1] + this.hitbox[1])];
|
||||
var hpos2 = [Math.floor(ent.pos[0] + ent.hitbox[0]), Math.floor(ent.pos[1] + ent.hitbox[1])];
|
||||
|
||||
//if the hitboxes actually overlap
|
||||
if (!(hpos1[0] > hpos2[0]+ent.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
||||
if (!(hpos1[1] > hpos2[1]+ent.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
||||
//if the entity is over the block, it's basically floor
|
||||
var center = hpos2[0] + ent.hitbox[2] / 2;
|
||||
if (Math.abs(hpos2[1] + ent.hitbox[3] - hpos1[1]) <= ent.vel[1]) {
|
||||
ent.vel[1] = 0;
|
||||
ent.pos[1] = hpos1[1] - ent.hitbox[3] - ent.hitbox[1];
|
||||
ent.standing = true;
|
||||
if (ent instanceof Mario.Player) {
|
||||
ent.jumping = 0;
|
||||
}
|
||||
} else if (Math.abs(hpos2[1] - hpos1[1] - this.hitbox[3]) > ent.vel[1] &&
|
||||
center + 2 >= hpos1[0] && center - 2 <= hpos1[0] + this.hitbox[2]) {
|
||||
//ent is under the block.
|
||||
ent.vel[1] = 0;
|
||||
ent.pos[1] = hpos1[1] + this.hitbox[3];
|
||||
if (ent instanceof Mario.Player) {
|
||||
ent.jumping = 0;
|
||||
}
|
||||
} else {
|
||||
//entity is hitting it from the side, we're a wall
|
||||
ent.collideWall(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//we COULD try to write some shenanigans so that the check gets put into the
|
||||
//collision code, but there won't ever be more than a handful of pipes in a level
|
||||
//so the performance hit of scanning all of them is miniscule.
|
||||
Pipe.prototype.update = function(dt) {
|
||||
if (this.destination) this.checkPipe();
|
||||
}
|
||||
|
||||
//http://stackoverflow.com/questions/11227809/why-is-processing-a-sorted-array-faster-than-an-unsorted-array
|
||||
//I honestly have no idea if javascript does this, but I feel like it makes sense
|
||||
//stylistically to prefer branching outside of loops when possible as convention
|
||||
|
||||
//TODO: edit the spritesheet so UP and LEFT pipes aren't backwards.
|
||||
Pipe.prototype.render = function(ctx, vX, vY) {
|
||||
switch (this.direction) {
|
||||
case "DOWN":
|
||||
this.endsection.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
for (var i = 1; i < this.length; i++) {
|
||||
this.midsection.render(ctx, this.pos[0], this.pos[1]+i*16, vX, vY)
|
||||
}
|
||||
break;
|
||||
case "UP":
|
||||
this.endsection.render(ctx, this.pos[0], this.pos[1]+16*(this.length-1), vX, vY)
|
||||
for (var i=0; i < this.length - 1; i++) {
|
||||
this.midsection.render(ctx, this.pos[0], this.pos[1]+i*16, vX, vY)
|
||||
}
|
||||
break;
|
||||
case "RIGHT":
|
||||
this.endsection.render(ctx, this.pos[0], this.pos[1], vX, vY)
|
||||
for (var i = 1; i < this.length; i++) {
|
||||
this.midsection.render(ctx, this.pos[0]+16*i, this.pos[1], vX, vY)
|
||||
}
|
||||
break;
|
||||
case "LEFT":
|
||||
this.endsection.render(ctx, this.pos[0]+16*(this.length-1), this.pos[1], vX, vY)
|
||||
for (var i = 0; i < this.legth-1; i++) {
|
||||
this.midsection.render(ctx, this.pos[0], this.pos[1]+i*16, vX, vY)
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
})();
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user