mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-20 02:37:41 -05:00
Compare commits
640 Commits
2022.05.1
...
fix-404-ge
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39725c1384 | ||
|
|
48c5158b46 | ||
|
|
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 | ||
|
|
5f319452d5 | ||
|
|
60d505d2d1 | ||
|
|
f64cc4dcae | ||
|
|
60e6f4293a | ||
|
|
00ab9a8d02 | ||
|
|
7d5f6c9ead | ||
|
|
a295edf19d | ||
|
|
b674515d06 | ||
|
|
d033ab04da | ||
|
|
304d76d088 | ||
|
|
978afdad97 | ||
|
|
d4e41e679d | ||
|
|
146264ff12 | ||
|
|
dcb107ae65 | ||
|
|
c236269d13 | ||
|
|
8f658e6d85 | ||
|
|
d203b60f44 | ||
|
|
a1a16aba74 | ||
|
|
6ded003447 | ||
|
|
4841e29fc6 | ||
|
|
0b014eea56 | ||
|
|
1c0be16f30 | ||
|
|
27ba8bea2f | ||
|
|
c566977749 | ||
|
|
5c1b785b4b | ||
|
|
8657dfb5da | ||
|
|
dfa837754e | ||
|
|
0a7df78770 | ||
|
|
066ecbe022 | ||
|
|
6c80db810f | ||
|
|
6023c413ab | ||
|
|
7910d040b6 | ||
|
|
5bd99f5224 | ||
|
|
f3157b377f | ||
|
|
e31e03afde | ||
|
|
eddde7c94c | ||
|
|
7be72ee4c1 | ||
|
|
6731467514 | ||
|
|
8dd699d235 | ||
|
|
6cb81b5c3d | ||
|
|
17187ba3ec | ||
|
|
531ee928b0 | ||
|
|
db806a5df9 | ||
|
|
9de154595a | ||
|
|
9e4cb79679 | ||
|
|
b7834073b8 | ||
|
|
b0e56577b5 | ||
|
|
ccb0e6b269 | ||
|
|
edfd4baa1f | ||
|
|
0f50f4a9fd | ||
|
|
47494e62a7 | ||
|
|
7aa25712d9 | ||
|
|
1db155570d | ||
|
|
1054e8e644 | ||
|
|
aa429f34d8 | ||
|
|
e351889811 | ||
|
|
24a70a8273 | ||
|
|
3f26657116 | ||
|
|
d41669af8b | ||
|
|
56466c2a00 | ||
|
|
fa7a97ca30 | ||
|
|
8aba271a42 | ||
|
|
8275aa2810 | ||
|
|
410ddf314c | ||
|
|
fa217bee20 | ||
|
|
817d0edc69 | ||
|
|
513dfe0b42 | ||
|
|
bd7a20309b | ||
|
|
a726be3c7c | ||
|
|
10f2054e9a | ||
|
|
2fa47f310d | ||
|
|
5b927a70c2 | ||
|
|
2a59ff8e68 | ||
|
|
e4d1befcdb | ||
|
|
844e04ff96 | ||
|
|
cc05a98b0e | ||
|
|
006d161a32 | ||
|
|
a4839db79a | ||
|
|
87e3b5b1dc | ||
|
|
faa900d502 | ||
|
|
a5275db3ec | ||
|
|
77e017a574 | ||
|
|
8ed8ddbf76 | ||
|
|
eb31978488 | ||
|
|
677d708588 | ||
|
|
ade0dca8f9 | ||
|
|
8e1cd0b268 | ||
|
|
9102768366 | ||
|
|
0c722b9164 | ||
|
|
b6f514451a | ||
|
|
c49fdfc56c | ||
|
|
676e04b28e | ||
|
|
6aa864a351 | ||
|
|
72acb4826c | ||
|
|
734be5f355 | ||
|
|
cede06ae19 | ||
|
|
19491d8010 | ||
|
|
c580aac991 | ||
|
|
032d1aaad7 | ||
|
|
afa216dc5e | ||
|
|
69339fe3de | ||
|
|
571bb2b294 | ||
|
|
91a09a09f7 | ||
|
|
9b3433f6ae | ||
|
|
ee9b0960f7 | ||
|
|
506ac2574f | ||
|
|
dc84d7c1b5 | ||
|
|
fcaa57307f | ||
|
|
d25e754beb | ||
|
|
7f6f411ea8 | ||
|
|
96a73e31f3 | ||
|
|
c7942d7d8f | ||
|
|
479348eec9 | ||
|
|
ebfed27630 | ||
|
|
8923485169 | ||
|
|
d62de26683 | ||
|
|
1dd9c5b009 | ||
|
|
01b64e18ab | ||
|
|
fa61339a49 | ||
|
|
deb2eee3ad | ||
|
|
829cc9f6f9 | ||
|
|
1c7ef6622b | ||
|
|
f54ae52b2a | ||
|
|
171ae3cabe | ||
|
|
f3888df88c | ||
|
|
9274f9ec08 | ||
|
|
6822105c70 | ||
|
|
d5d855e4c3 | ||
|
|
1e09ac4fd3 | ||
|
|
bc513400c5 | ||
|
|
715ceb9ed4 | ||
|
|
0115b152a8 | ||
|
|
e1622a56fa | ||
|
|
03fee56a54 | ||
|
|
d00171a629 | ||
|
|
fa28b218ec | ||
|
|
eb882170d5 | ||
|
|
48a565a51d | ||
|
|
f60dd6a788 | ||
|
|
d6a88d4c9e | ||
|
|
4b4ff08131 | ||
|
|
698478ef95 | ||
|
|
4ab9ab51f6 | ||
|
|
bf3995d45c | ||
|
|
4fe603bf96 | ||
|
|
0639827d00 | ||
|
|
eaacd45672 | ||
|
|
5d733ab915 | ||
|
|
1bf6cc0e72 | ||
|
|
a9470ed9c1 | ||
|
|
2c5ef95027 | ||
|
|
f712b1369a | ||
|
|
2f03b18619 | ||
|
|
8cd5ba6361 | ||
|
|
c951961a92 | ||
|
|
3b68e1b27d | ||
|
|
48e6b1a84e | ||
|
|
ee46b46234 | ||
|
|
db49fd498a | ||
|
|
e95b90363e | ||
|
|
82c0d741e4 | ||
|
|
87b150d539 | ||
|
|
508a7d8605 | ||
|
|
9119939c3d | ||
|
|
59fc667651 | ||
|
|
0d946f853f | ||
|
|
b767a78b05 | ||
|
|
39774a83c5 | ||
|
|
c04015899b | ||
|
|
6898daf0ce | ||
|
|
eb3a31a698 | ||
|
|
0476627f34 | ||
|
|
eba42ad9b4 | ||
|
|
ca909b4f6b |
63
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
63
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
name: Bug Report
|
||||||
|
description: Create a report to help us improve
|
||||||
|
labels: ["type: bug", "needs-triage"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Thanks for helping PyScript! 🐍
|
||||||
|
|
||||||
|
Going through bugs 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 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 solution or duplication
|
||||||
|
required: true
|
||||||
|
- label: I already searched in Google and didn't find any good information or help
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: what-happened
|
||||||
|
attributes:
|
||||||
|
label: What happened?
|
||||||
|
description: And what should have happened instead? This really helps everyone review quicker and greatly increases the chance that someone can get around to solve your issue
|
||||||
|
placeholder: Tell us what you see!
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: browsers
|
||||||
|
attributes:
|
||||||
|
label: What browsers are you seeing the problem on? (if applicable)
|
||||||
|
multiple: true
|
||||||
|
options:
|
||||||
|
- Firefox
|
||||||
|
- Chrome
|
||||||
|
- Safari
|
||||||
|
- Microsoft Edge
|
||||||
|
- Other
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
id: list
|
||||||
|
attributes:
|
||||||
|
label: Console info
|
||||||
|
description: |
|
||||||
|
If there are errors in your browser console then its helpful to be able to troubleshoot.
|
||||||
|
- 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
|
||||||
|
id: context
|
||||||
|
attributes:
|
||||||
|
label: Additional Context
|
||||||
|
description: Add any additional context information or screenshots you think are useful.
|
||||||
23
.github/ISSUE_TEMPLATE/bug_report.md
vendored
23
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,23 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Create a report to help us improve
|
|
||||||
title: "[BUG]"
|
|
||||||
labels: needs-triage
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Describe the bug**
|
|
||||||
A clear and concise description of what the bug is.
|
|
||||||
|
|
||||||
**To Reproduce**
|
|
||||||
Steps to reproduce the behavior: either a code snippet or a link to an HTML page which shows the bug.
|
|
||||||
|
|
||||||
**Expected behavior**
|
|
||||||
A clear and concise description of what you expected to happen.
|
|
||||||
|
|
||||||
**Screenshots**
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context about the problem here.
|
|
||||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
blank_issues_enabled: true
|
||||||
|
contact_links:
|
||||||
|
- 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
|
||||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Suggest an idea for this project
|
|
||||||
title: "[FEATURE]"
|
|
||||||
labels: needs-triage
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
|
||||||
A clear and concise description of what the problem is. Ex. As a user, I'd like to [...]
|
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
|
||||||
A clear and concise description of what you expect to happen.
|
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
|
||||||
A clear and concise description of any alternative solutions or features you've considered.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context or screenshots about the feature request here.
|
|
||||||
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)
|
||||||
5
.github/release.yml
vendored
Normal file
5
.github/release.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
changelog:
|
||||||
|
categories:
|
||||||
|
- title: New Features
|
||||||
|
- title: Breaking Changes
|
||||||
|
- title: Known Issues
|
||||||
56
.github/workflows/build-alpha.yml
vendored
56
.github/workflows/build-alpha.yml
vendored
@@ -1,56 +0,0 @@
|
|||||||
name: '[CI] Build Alpha'
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
tags:
|
|
||||||
- '**' # Currently any tag, need to slim down
|
|
||||||
paths:
|
|
||||||
- pyscriptjs/**
|
|
||||||
- .github/workflows/build-alpha.yml # Test that workflow works when changed
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
id-token: write
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: pyscriptjs
|
|
||||||
|
|
||||||
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: Install dependencies
|
|
||||||
run: |
|
|
||||||
npm install
|
|
||||||
- name: Build pyscript
|
|
||||||
run: |
|
|
||||||
npm run 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 ./examples/build/ s3://pyscript.net/alpha/
|
|
||||||
63
.github/workflows/build-latest.yml
vendored
63
.github/workflows/build-latest.yml
vendored
@@ -1,63 +0,0 @@
|
|||||||
name: '[CI] Build Latest'
|
|
||||||
|
|
||||||
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 in pyscriptjs/
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- pyscriptjs/**
|
|
||||||
- .github/workflows/build-latest.yml # Test that workflow works when changed
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
id-token: write
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: pyscriptjs
|
|
||||||
|
|
||||||
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: Install dependencies
|
|
||||||
run: |
|
|
||||||
npm install
|
|
||||||
- name: Build pyscript
|
|
||||||
run: |
|
|
||||||
npm run build
|
|
||||||
|
|
||||||
# Deploy to S3
|
|
||||||
- name: Configure AWS credentials
|
|
||||||
if: github.ref == 'refs/heads/main' # Only deploy on merge into main
|
|
||||||
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
|
|
||||||
if: github.ref == 'refs/heads/main'
|
|
||||||
run: aws s3 sync --quiet ./examples/build/ s3://pyscript.net/unstable
|
|
||||||
56
.github/workflows/prepare-release.yml
vendored
Normal file
56
.github/workflows/prepare-release.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
name: "Prepare Release"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "[0-9][0-9][0-9][0-9].[0-9][0-9].[0-9]+" # YYYY.MM.MICRO
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./pyscript.core
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
prepare-release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
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
|
||||||
|
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
|
||||||
|
with:
|
||||||
|
draft: true
|
||||||
|
prerelease: true
|
||||||
|
generate_release_notes: true
|
||||||
|
files: ./build.zip
|
||||||
59
.github/workflows/publish-release.yml
vendored
Normal file
59
.github/workflows/publish-release.yml
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
name: "Publish Release"
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./pyscript.core
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish-release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
contents: read
|
||||||
|
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/releases/${{ github.ref_name }}/#' ./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:
|
||||||
|
| # 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 }}/
|
||||||
61
.github/workflows/publish-snapshot.yml
vendored
Normal file
61
.github/workflows/publish-snapshot.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
name: "Publish Snapshot"
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
snapshot_version:
|
||||||
|
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:
|
||||||
|
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@v4
|
||||||
|
with:
|
||||||
|
aws-region: ${{ secrets.AWS_REGION }}
|
||||||
|
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||||
|
|
||||||
|
- 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 ./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/
|
||||||
33
.github/workflows/sync-examples.yml
vendored
33
.github/workflows/sync-examples.yml
vendored
@@ -1,33 +0,0 @@
|
|||||||
name: '[CI] Sync Examples'
|
|
||||||
|
|
||||||
on:
|
|
||||||
push: # Only run on merges into main that modify files under pyscriptjs/examples/
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- pyscriptjs/examples/**
|
|
||||||
- .github/workflows/sync-examples.yml # Test that workflow works when changed
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
id-token: write
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: pyscriptjs/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
|
||||||
15
.gitignore
vendored
15
.gitignore
vendored
@@ -71,6 +71,7 @@ instance/
|
|||||||
|
|
||||||
# Sphinx documentation
|
# Sphinx documentation
|
||||||
docs/_build/
|
docs/_build/
|
||||||
|
docs/_env/
|
||||||
|
|
||||||
# PyBuilder
|
# PyBuilder
|
||||||
target/
|
target/
|
||||||
@@ -134,3 +135,17 @@ dmypy.json
|
|||||||
.pyre/
|
.pyre/
|
||||||
|
|
||||||
node_modules/
|
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,77 +1,53 @@
|
|||||||
# This is the configuration for pre-commit, a local framework for managing pre-commit hooks
|
# This is the configuration for pre-commit, a local framework for managing pre-commit hooks
|
||||||
# Check out the docs at: https://pre-commit.com/
|
# Check out the docs at: https://pre-commit.com/
|
||||||
|
ci:
|
||||||
|
#skip: [eslint]
|
||||||
|
autoupdate_schedule: monthly
|
||||||
|
|
||||||
default_stages: [commit]
|
default_stages: [commit]
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.2.0
|
rev: v4.4.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-builtin-literals
|
- id: check-builtin-literals
|
||||||
- id: check-case-conflict
|
- id: check-case-conflict
|
||||||
- id: check-docstring-first
|
- id: check-docstring-first
|
||||||
- id: check-executables-have-shebangs
|
- id: check-executables-have-shebangs
|
||||||
- id: check-json
|
- id: check-json
|
||||||
exclude: tsconfig.json
|
exclude: tsconfig\.json
|
||||||
- id: check-toml
|
- id: check-toml
|
||||||
- id: check-xml
|
exclude: bad\.toml
|
||||||
- id: check-yaml
|
- id: check-xml
|
||||||
- id: detect-private-key
|
- id: check-yaml
|
||||||
- id: end-of-file-fixer
|
- id: detect-private-key
|
||||||
exclude: \.min\.js$
|
- id: end-of-file-fixer
|
||||||
- id: trailing-whitespace
|
exclude: pyscript\.core/dist|\.min\.js$
|
||||||
|
- id: trailing-whitespace
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/bandit
|
- repo: https://github.com/psf/black
|
||||||
rev: 1.7.4
|
rev: 23.1.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: bandit
|
- id: black
|
||||||
args:
|
exclude: pyscript\.core/src/stdlib/pyscript/__init__\.py
|
||||||
- --skip=B201
|
|
||||||
|
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/codespell-project/codespell
|
||||||
rev: 22.3.0
|
rev: v2.2.4
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: codespell # See 'pyproject.toml' for args
|
||||||
|
exclude: \.js\.map$
|
||||||
|
additional_dependencies:
|
||||||
|
- tomli
|
||||||
|
|
||||||
- repo: https://github.com/codespell-project/codespell
|
- repo: https://github.com/hoodmane/pyscript-prettier-precommit
|
||||||
rev: v2.1.0
|
rev: "v3.0.0-alpha.6"
|
||||||
hooks:
|
hooks:
|
||||||
- id: codespell # See 'setup.cfg' for args
|
- 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/flake8
|
- repo: https://github.com/pycqa/isort
|
||||||
rev: 4.0.1
|
rev: 5.12.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8 # See 'setup.cfg' for args
|
- id: isort
|
||||||
additional_dependencies: [flake8-bugbear, flake8-comprehensions]
|
name: isort (python)
|
||||||
|
args: [--profile, black]
|
||||||
- repo: https://github.com/pycqa/isort
|
|
||||||
rev: 5.10.1
|
|
||||||
hooks:
|
|
||||||
- id: isort
|
|
||||||
name: isort (python)
|
|
||||||
args: [--profile, black]
|
|
||||||
|
|
||||||
- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
|
|
||||||
rev: v2.3.0
|
|
||||||
hooks:
|
|
||||||
- id: pretty-format-yaml
|
|
||||||
args: [--autofix, --indent, '4']
|
|
||||||
|
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
|
||||||
rev: v2.32.1
|
|
||||||
hooks:
|
|
||||||
- id: pyupgrade
|
|
||||||
args:
|
|
||||||
- --py310-plus
|
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/mirrors-eslint
|
|
||||||
rev: v8.15.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'
|
|
||||||
|
|||||||
5
.prettierignore
Normal file
5
.prettierignore
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
ISSUE_TEMPLATE
|
||||||
|
*.min.*
|
||||||
|
package-lock.json
|
||||||
|
docs
|
||||||
|
examples/panel.html
|
||||||
28
.readthedocs.yml
Normal file
28
.readthedocs.yml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# .readthedocs.yaml
|
||||||
|
# Read the Docs configuration file
|
||||||
|
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||||
|
|
||||||
|
# Required
|
||||||
|
version: 2
|
||||||
|
|
||||||
|
# Set the version of Python and other tools you might need
|
||||||
|
build:
|
||||||
|
os: ubuntu-20.04
|
||||||
|
tools:
|
||||||
|
python: miniconda3-4.7
|
||||||
|
|
||||||
|
# Build documentation in the docs/ directory with Sphinx
|
||||||
|
sphinx:
|
||||||
|
configuration: docs/conf.py
|
||||||
|
|
||||||
|
conda:
|
||||||
|
environment: docs/environment.yml
|
||||||
|
|
||||||
|
# If using Sphinx, optionally build your docs in additional formats such as PDF
|
||||||
|
# formats:
|
||||||
|
# - pdf
|
||||||
|
|
||||||
|
# Optionally declare the Python requirements required to build your docs
|
||||||
|
python:
|
||||||
|
install:
|
||||||
|
- requirements: docs/requirements.txt
|
||||||
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))
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Code of Conduct
|
# Code of Conduct
|
||||||
|
|
||||||
The Code of Conduct is available in the pyscript Governance repo.
|
The Code of Conduct is available in the PyScript Governance repo.
|
||||||
See https://github.com/pyscript/governance/blob/main/CODE-OF-CONDUCT.md
|
See https://github.com/pyscript/governance/blob/main/CODE-OF-CONDUCT.md
|
||||||
|
|||||||
@@ -4,81 +4,64 @@ Thank you for wanting to contribute to the PyScript project!
|
|||||||
|
|
||||||
## Table of contents
|
## Table of contents
|
||||||
|
|
||||||
* [Code of Conduct](#code-of-conduct)
|
- [Contributing to PyScript](#contributing-to-pyscript)
|
||||||
* [Contributing](#contributing)
|
- [Table of contents](#table-of-contents)
|
||||||
* [Reporting bugs](#reporting-bugs)
|
- [Code of Conduct](#code-of-conduct)
|
||||||
* [Reporting security issues](#reporting-security-issues)
|
- [Contributing](#contributing)
|
||||||
* [Asking questions](#asking-questions)
|
- [Reporting bugs](#reporting-bugs)
|
||||||
* [Setting up your environment](#setting-up-your-environment)
|
- [Creating useful issues](#creating-useful-issues)
|
||||||
* [Places to start](#places-to-start)
|
- [Reporting security issues](#reporting-security-issues)
|
||||||
* [Submitting a change](#submitting-a-change)
|
- [Asking questions](#asking-questions)
|
||||||
* [License terms for contributions](#license-terms-for-contributions)
|
- [Setting up your local environment and developing](#setting-up-your-local-environment-and-developing)
|
||||||
* [Becoming a maintainer](#becoming-a-maintainer)
|
- [Developing](#developing)
|
||||||
* [Trademarks](#trademarks)
|
- [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
|
# Code of Conduct
|
||||||
|
|
||||||
The [PyScript Code of Conduct](https://github.com/pyscript/governance/blob/main/CODE-OF-CONDUCT.md) governs the project and everyone participating in it. By participating, you are expected to uphold this code. Please report unacceptable behavior to the maintainers or administrators as described in that document.
|
The [PyScript Code of Conduct](https://github.com/pyscript/governance/blob/main/CODE-OF-CONDUCT.md) governs the project and everyone participating in it. By participating, you are expected to uphold this code. Please report unacceptable behavior to the maintainers or administrators as described in that document.
|
||||||
|
|
||||||
## Contributing
|
# Contributing
|
||||||
|
|
||||||
### Reporting bugs
|
## Reporting bugs
|
||||||
|
|
||||||
Bugs are tracked on the [project issues page](https://github.com/pyscript/pyscript/issues). Please check if your issue has already been filed by someone else by searching the existing issues before filing a new one. Once your issue is filed, it will be triaged by another contributor or maintainer. If there are questions raised about your issue, please respond promptly.
|
Bugs are tracked on the [project issues page](https://github.com/pyscript/pyscript/issues). Please check if your issue has already been filed by someone else by searching the existing issues before filing a new one. Once your issue is filed, it will be triaged by another contributor or maintainer. If there are questions raised about your issue, please respond promptly.
|
||||||
|
|
||||||
#### Creating useful issues
|
## Creating useful issues
|
||||||
|
|
||||||
* Use a clear and descriptive title.
|
- 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 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.
|
- Describe the behavior you observed, and the behavior you had expected.
|
||||||
* Include screenshots if they help make the issue clear.
|
- Include screenshots if they help make the issue clear.
|
||||||
|
|
||||||
### Reporting security issues
|
## Reporting security issues
|
||||||
|
|
||||||
If you aren't confident that it is appropriate to submit a security issue using the above process, you can e-mail it to security@pyscript.net
|
If you aren't confident that it is appropriate to submit a security issue using the above process, you can e-mail it to security@pyscript.net
|
||||||
|
|
||||||
### Asking questions
|
## Asking questions
|
||||||
|
|
||||||
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).
|
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 environment
|
## Places to start
|
||||||
|
|
||||||
* clone the repo
|
If you would like to contribute to PyScript, but you aren't sure where to begin, here are some suggestions:
|
||||||
```
|
|
||||||
git clone https://github.com/pyscript/pyscript
|
|
||||||
```
|
|
||||||
* cd into the main project folder
|
|
||||||
```
|
|
||||||
cd pyscript/pyscriptjs
|
|
||||||
```
|
|
||||||
* install the dependencies with npm install - make sure to use nodejs version >= 16
|
|
||||||
```
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
* 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
|
|
||||||
```
|
|
||||||
|
|
||||||
### Places to start
|
- **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.
|
||||||
|
|
||||||
If you would like to contribute to PyScript, but you aren't sure where to begin, here are some suggestions.
|
## Setting up your local environment and developing
|
||||||
|
|
||||||
* **Read over the existing documentation.** Are there things missing, or could they be clearer? Make some changes/additions to those documents.
|
If you would like to contribute to PyScript, you will need to set up a local development environment. The [following instructions](https://docs.pyscript.net/latest/development/setting-up-environment.html) will help you get started.
|
||||||
* **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
|
You can also read about PyScript's [development process](https://docs.pyscript.net/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!
|
||||||
|
|
||||||
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).
|
|
||||||
|
|
||||||
To create a change for PyScript, you can follow the process described [here](https://docs.github.com/en/get-started/quickstart/contributing-to-projects).
|
|
||||||
|
|
||||||
* Fork a personal copy of the PyScript project.
|
|
||||||
* Make the changes you would like (don't forget to test them!)
|
|
||||||
* Please squash all commits for a change into a single commit (this can be done using "git rebase -i"). Do your best to have a well-formed commit message for the change.
|
|
||||||
* Open a pull request back to the PyScript project and address any comments/questions from the maintainers and other contributors.
|
|
||||||
|
|
||||||
## License terms for contributions
|
## License terms for contributions
|
||||||
|
|
||||||
@@ -86,12 +69,13 @@ This Project welcomes contributions, suggestions, and feedback. All contribution
|
|||||||
|
|
||||||
## Becoming a maintainer
|
## Becoming a maintainer
|
||||||
|
|
||||||
Contributors are invited to be maintainers to 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.
|
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.
|
||||||
|
|
||||||
## Trademarks
|
## Trademarks
|
||||||
|
|
||||||
The Project abides by the Organization's [trademark policy](https://github.com/pyscript/governance/blob/main/TRADEMARKS.md).
|
The Project abides by the Organization's [trademark policy](https://github.com/pyscript/governance/blob/main/TRADEMARKS.md).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Part of MVG-0.1-beta.
|
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/).
|
Made with love by GitHub. Licensed under the [CC-BY 4.0 License](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||||
|
|||||||
@@ -1,210 +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/).
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
There is no installation required. In this document we'll use
|
|
||||||
the PyScript assets served on https://pyscript.net.
|
|
||||||
|
|
||||||
If you want to download the source and build it yourself, follow
|
|
||||||
the instructions in the 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/alpha/pyscript.css" />
|
|
||||||
<script defer src="https://pyscript.net/alpha/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 8 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/alpha/pyscript.css" />
|
|
||||||
<script defer src="https://pyscript.net/alpha/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 and it printed
|
|
||||||
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 place holders for
|
|
||||||
the `<py-script>` tag write to.
|
|
||||||
|
|
||||||
```html
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
|
|
||||||
<script defer src="https://pyscript.net/alpha/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>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Packages and modules
|
|
||||||
|
|
||||||
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>` 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/pyscriptjs/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/alpha/pyscript.css" />
|
|
||||||
<script defer src="https://pyscript.net/alpha/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
|
|
||||||
|
|
||||||
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/alpha/pyscript.css" />
|
|
||||||
<script defer src="https://pyscript.net/alpha/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>
|
|
||||||
```
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Governance Policy
|
# Governance Policy
|
||||||
|
|
||||||
This document provides the governance policy for the Project. Maintainers agree to this policy and to abide by all Project polices, including the [code of conduct](https://github.com/pyscript/governance/blob/main/CODE-OF-CONDUCT.md), [trademark policy](https://github.com/pyscript/governance/blob/main/TRADEMARKS.md), and [antitrust policy](https://github.com/pyscript/governance/blob/main/ANTITRUST.md) by adding their name to the [maintainers.md file](./MAINTAINERS.md).
|
This document provides the governance policy for the Project. Maintainers agree to this policy and to abide by all Project policies, including the [code of conduct](https://github.com/pyscript/governance/blob/main/CODE-OF-CONDUCT.md), [trademark policy](https://github.com/pyscript/governance/blob/main/TRADEMARKS.md), and [antitrust policy](https://github.com/pyscript/governance/blob/main/ANTITRUST.md) by adding their name to the [maintainers.md file](https://github.com/pyscript/pyscript/blob/main/MAINTAINERS.md).
|
||||||
|
|
||||||
## 1. Roles.
|
## 1. Roles.
|
||||||
|
|
||||||
@@ -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.
|
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.
|
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/).
|
Made with love by GitHub. Licensed under the [CC-BY 4.0 License](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||||
|
|||||||
@@ -1,17 +1,24 @@
|
|||||||
# Maintainers
|
# Maintainers
|
||||||
|
|
||||||
This document lists the Maintainers of the Project. Maintainers may be added once approved by the existing maintainers as described in the [Governance document](./GOVERNANCE.md). By adding your name to this list you are agreeing to abide by the Project governance documents and to abide by all of the Organization's polices, including the [code of conduct](https://github.com/pyscript/governance/blob/main/CODE-OF-CONDUCT.md), [trademark policy](https://github.com/pyscript/governance/blob/main/TRADEMARKS.md), and [antitrust policy](https://github.com/pyscript/governance/blob/main/TRADEMARKS.md). If you are participating because of your affiliation with another organization (designated below), you represent that you have the authority to bind that organization to these policies.
|
This document lists the Maintainers of the Project. Maintainers may be added once approved by the existing maintainers as described in the [Governance document](https://github.com/pyscript/pyscript/blob/main/GOVERNANCE.md). By adding your name to this list you are agreeing to abide by the Project governance documents and to abide by all of the Organization's polices, including the [code of conduct](https://github.com/pyscript/governance/blob/main/CODE-OF-CONDUCT.md), [trademark policy](https://github.com/pyscript/governance/blob/main/TRADEMARKS.md), and [antitrust policy](https://github.com/pyscript/governance/blob/main/TRADEMARKS.md). If you are participating because of your affiliation with another organization (designated below), you represent that you have the authority to bind that organization to these policies.
|
||||||
|
|
||||||
| **NAME** | **Organization** |
|
| **NAME** | **Organization** |
|
||||||
| --- | --- |
|
| -------------------- | ---------------- |
|
||||||
| Fabio Pliger | Anaconda, Inc |
|
| Fabio Pliger | Anaconda, Inc |
|
||||||
| Antonio Cuni | Anaconda, Inc |
|
| Antonio Cuni | Anaconda, Inc |
|
||||||
| Philipp Rudiger | Anaconda, Inc |
|
| Philipp Rudiger | Anaconda, Inc |
|
||||||
| Peter Wang | Anaconda, Inc |
|
| Peter Wang | Anaconda, Inc |
|
||||||
| Kevin Goldsmith | 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 | |
|
||||||
|
| Paul Everitt | |
|
||||||
|
| Fabio Rosado | Anaconda, Inc |
|
||||||
|
| Andrea Giammarchi | Anaconda, Inc |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Part of MVG-0.1-beta.
|
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/).
|
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)
|
||||||
70
README.md
70
README.md
@@ -3,43 +3,81 @@
|
|||||||
## What is PyScript
|
## What is PyScript
|
||||||
|
|
||||||
### Summary
|
### Summary
|
||||||
PyScript is a Pythonic alternative to Scratch, JSFiddle, and other "easy to use" programming frameworks, with the goal of making the web a friendly, hackable place where anyone can author interesting and interactive applications.
|
|
||||||
|
|
||||||
To get started see [GETTING-STARTED](GETTING-STARTED.md).
|
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.
|
||||||
|
|
||||||
For examples see [the pyscript folder](pyscriptjs).
|
To get started see the [getting started tutorial](https://pyscript.github.io/docs/latest/beginning-pyscript/).
|
||||||
|
|
||||||
|
For examples see [here](examples).
|
||||||
|
|
||||||
### Longer Version
|
### 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.
|
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
|
## Try PyScript
|
||||||
|
|
||||||
To try PyScript, import the appropriate pyscript files to your html page with:
|
To try PyScript, import the appropriate pyscript files into the `<head>` tag of your html page:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
|
<head>
|
||||||
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://pyscript.net/releases/2023.11.1/core.css"
|
||||||
|
/>
|
||||||
|
<script
|
||||||
|
type="module"
|
||||||
|
src="https://pyscript.net/releases/2023.11.1/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
|
You can then use PyScript components in your html page. PyScript currently offers various ways of running Python code:
|
||||||
* `<py-repl>`: creates a REPL component that is rendered to the page as a code editor and allows users to write executable code
|
|
||||||
|
|
||||||
Check out the [pyscriptjs/examples](pyscriptjs/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 if 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
|
## How to Contribute
|
||||||
|
|
||||||
To contribute see the [CONTRIBUTING](CONTRIBUTING.md) document.
|
Read the [contributing guide](CONTRIBUTING.md) to learn about our development process, reporting bugs and improvements, creating issues and asking questions.
|
||||||
|
|
||||||
|
Check out the [developing process](https://docs.pyscript.net/latest/contributing) documentation for more information on how to setup your development environment.
|
||||||
|
|
||||||
|
## Community calls and events
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
## Resources
|
## Resources
|
||||||
|
|
||||||
* [Discussion board](https://community.anaconda.cloud/c/tech-topics/pyscript)
|
- [Official docs](https://docs.pyscript.net)
|
||||||
* [Home Page](https://pyscript.net/)
|
- [Discussion board](https://community.anaconda.cloud/c/tech-topics/pyscript)
|
||||||
* [Blog Post](https://engineering.anaconda.com/2022/04/welcome-pyscript.html)
|
- [Home Page](https://pyscript.net/)
|
||||||
|
- [Blog Post](https://engineering.anaconda.com/2022/04/welcome-pyscript.html)
|
||||||
|
- [Discord Channel](https://discord.gg/BYB2kvyFwm)
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
* This is an extremely experimental project, so expect things to break!
|
- This is an extremely experimental project, so expect things to break!
|
||||||
* PyScript has been only tested on Chrome at the moment.
|
- PyScript has been only tested on Chrome at the moment.
|
||||||
|
|
||||||
## Governance
|
## Governance
|
||||||
|
|
||||||
|
|||||||
19
TROUBLESHOOTING.md
Normal file
19
TROUBLESHOOTING.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Troubleshooting
|
||||||
|
|
||||||
|
This page is meant for troubleshooting common problems with PyScript.
|
||||||
|
|
||||||
|
## Table of contents:
|
||||||
|
|
||||||
|
- [Make Setup](#make-setup)
|
||||||
|
|
||||||
|
## Make setup
|
||||||
|
|
||||||
|
A lot of problems related to `make setup` are related to node and npm being outdated. Once npm and node are updated, `make setup` should work. You can follow the steps on the [npm documentation](https://docs.npmjs.com/try-the-latest-stable-version-of-npm) to update npm (the update command for Linux should work for Mac as well). Once npm has been updated you can continue to the instructions to update node below.
|
||||||
|
|
||||||
|
To update Node run the following commands in order (Most likely you'll be prompted for your user password, this is normal):
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo npm cache clean -f
|
||||||
|
sudo npm install -g n
|
||||||
|
sudo n stable
|
||||||
|
```
|
||||||
90
examples/altair.html
Normal file
90
examples/altair.html
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<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"
|
||||||
|
/>
|
||||||
|
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||||
|
<style>
|
||||||
|
py-script {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script
|
||||||
|
type="module"
|
||||||
|
src="https://esm.sh/@pyscript/core@latest/core.js"
|
||||||
|
></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar" style="background-color: #000000">
|
||||||
|
<div class="app-header">
|
||||||
|
<a href="/">
|
||||||
|
<img src="./logo.png" class="logo" />
|
||||||
|
</a>
|
||||||
|
<a class="title" href="" style="color: #f0ab3c">Altair</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<section class="pyscript">
|
||||||
|
<div id="altair"></div>
|
||||||
|
<py-tutor>
|
||||||
|
<py-config>
|
||||||
|
packages = [
|
||||||
|
"altair",
|
||||||
|
"pandas",
|
||||||
|
"vega_datasets"
|
||||||
|
]
|
||||||
|
plugins = [
|
||||||
|
"https://pyscript.net/latest/plugins/python/py_tutor.py"
|
||||||
|
]
|
||||||
|
</py-config>
|
||||||
|
<py-script>
|
||||||
|
from pyscript import display
|
||||||
|
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)
|
||||||
|
|
||||||
|
display(alt.vconcat(
|
||||||
|
rect + circ,
|
||||||
|
bar
|
||||||
|
).resolve_legend(
|
||||||
|
color="independent",
|
||||||
|
size="independent"
|
||||||
|
), target="altair")
|
||||||
|
</py-script>
|
||||||
|
</py-tutor>
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
39
examples/antigravity.html
Normal file
39
examples/antigravity.html
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<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"
|
||||||
|
/>
|
||||||
|
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||||
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar" style="background-color: #000000">
|
||||||
|
<div class="app-header">
|
||||||
|
<a href="/">
|
||||||
|
<img src="./logo.png" class="logo" />
|
||||||
|
</a>
|
||||||
|
<a class="title" href="" style="color: #f0ab3c">Antigravity</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<py-tutor modules="antigravity.py">
|
||||||
|
<section class="pyscript">
|
||||||
|
<py-config>
|
||||||
|
plugins = [
|
||||||
|
"https://pyscript.net/latest/plugins/python/py_tutor.py"
|
||||||
|
]
|
||||||
|
[[fetch]]
|
||||||
|
files = ["./antigravity.py"]
|
||||||
|
</py-config>
|
||||||
|
<b>Based on xkcd: antigravity https://xkcd.com/353/.</b>
|
||||||
|
<py-script>
|
||||||
|
import antigravity
|
||||||
|
antigravity.fly()
|
||||||
|
</py-script>
|
||||||
|
</section>
|
||||||
|
</py-tutor>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,19 +1,18 @@
|
|||||||
import random
|
import random
|
||||||
import sys
|
|
||||||
|
|
||||||
from js import DOMParser, document, setInterval
|
from js import DOMParser, document, setInterval
|
||||||
from pyodide import create_proxy
|
from pyodide.ffi import create_proxy
|
||||||
from pyodide.http import open_url
|
from pyodide.http import open_url
|
||||||
|
|
||||||
|
|
||||||
class Antigravity:
|
class Antigravity:
|
||||||
|
|
||||||
url = "./antigravity.svg"
|
url = "./antigravity.svg"
|
||||||
|
|
||||||
def __init__(self, target=None, interval=10, append=True, fly=False):
|
def __init__(self, target=None, interval=10, append=True, fly=False):
|
||||||
target = target or sys.stdout._out
|
|
||||||
self.target = (
|
self.target = (
|
||||||
document.getElementById(target) if isinstance(target, str) else target
|
document.getElementById(target)
|
||||||
|
if isinstance(target, str)
|
||||||
|
else document.body
|
||||||
)
|
)
|
||||||
doc = DOMParser.new().parseFromString(
|
doc = DOMParser.new().parseFromString(
|
||||||
open_url(self.url).read(), "image/svg+xml"
|
open_url(self.url).read(), "image/svg+xml"
|
||||||
|
Before Width: | Height: | Size: 212 KiB After Width: | Height: | Size: 212 KiB |
91
examples/assets/css/examples.css
Normal file
91
examples/assets/css/examples.css
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pyscript {
|
||||||
|
margin: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code {
|
||||||
|
display: flex;
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
|
z-index: 9998;
|
||||||
|
top: 7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1300px) {
|
||||||
|
.code:has(> .code-section-visible) {
|
||||||
|
width: 90%;
|
||||||
|
/* Absolute position is messing up the layout on small screens */
|
||||||
|
right: 70px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-section-hidden {
|
||||||
|
width: 0px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-section-visible {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
background-color: rgb(45 46 53 / 90%);
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 10px 0px 0px 10px;
|
||||||
|
color: #c6c6c8;
|
||||||
|
}
|
||||||
|
.code-section-visible p {
|
||||||
|
margin: 0;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: small;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-html,
|
||||||
|
.language-python {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#view-code-button {
|
||||||
|
writing-mode: tb-rl;
|
||||||
|
text-orientation: sideways-right;
|
||||||
|
background-color: #1d1d22;
|
||||||
|
color: white;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 81px;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
position: sticky;
|
||||||
|
width: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
padding-right: 10px;
|
||||||
|
font-size: 28px;
|
||||||
|
height: 30px;
|
||||||
|
max-width: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
text-decoration: none;
|
||||||
|
text-decoration-line: none;
|
||||||
|
text-decoration-style: initial;
|
||||||
|
text-decoration-color: initial;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 1.5em;
|
||||||
|
line-height: 2em;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
}
|
||||||
74
examples/assets/css/index.css
Normal file
74
examples/assets/css/index.css
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
.example {
|
||||||
|
margin-bottom: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example h2 {
|
||||||
|
/* color: #000000; */
|
||||||
|
font-family: "Inconsolata", monospace;
|
||||||
|
font-size: 2.25rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
height: 15rem;
|
||||||
|
background-color: var(--color-secondary);
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover,
|
||||||
|
.card:hover a,
|
||||||
|
.card:hover a:visited,
|
||||||
|
.card:hover h2 {
|
||||||
|
background-color: var(--color-primary);
|
||||||
|
color: #1d1d22;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card a h2 {
|
||||||
|
color: var(--color-primary);
|
||||||
|
margin: 0;
|
||||||
|
font-family: "Inconsolata", monospace;
|
||||||
|
font-size: 2.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card a p {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
a .card {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content a,
|
||||||
|
.card-content a:visited {
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
examples/assets/css/main.css
Normal file
25
examples/assets/css/main.css
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
@import url("https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;700&display=swap");
|
||||||
|
@import "./variables.css";
|
||||||
|
@import "./reset.css";
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: #2d2e35
|
||||||
|
url("https://assets.anaconda.com/production/Content/1650828148240.png?w=3240&auto=compress%2Cformat&fit=crop&dm=1650828161&s=c558dc55e0ed1f8419a892e842a5728f")
|
||||||
|
repeat-x center bottom / 250px;
|
||||||
|
background-attachment: fixed;
|
||||||
|
overflow-x: hidden;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1510px;
|
||||||
|
margin: auto;
|
||||||
|
padding: 0 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-main {
|
||||||
|
font-size: 4.25rem;
|
||||||
|
font-family: "Inconsolata", monospace;
|
||||||
|
text-align: center;
|
||||||
|
margin: 2rem 0;
|
||||||
|
}
|
||||||
22
examples/assets/css/reset.css
Normal file
22
examples/assets/css/reset.css
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
*,
|
||||||
|
*: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;
|
||||||
|
}
|
||||||
6
examples/assets/css/variables.css
Normal file
6
examples/assets/css/variables.css
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
:root {
|
||||||
|
--color-primary: #fda703;
|
||||||
|
--color-secondary: #1d1d22;
|
||||||
|
--text-color: white;
|
||||||
|
--card-shadow: 0px 5px 11px 0px rgb(0 0 0 / 15%);
|
||||||
|
}
|
||||||
3
examples/assets/prism/prism.min.css
vendored
Normal file
3
examples/assets/prism/prism.min.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
/* PrismJS 1.29.0
|
||||||
|
https://prismjs.com/download.html#themes=prism-okaidia&languages=markup+clike+javascript+python */
|
||||||
|
code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:0 0;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#272822}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8292a2}.token.punctuation{color:#f8f8f2}.token.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#f92672}.token.boolean,.token.number{color:#ae81ff}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#a6e22e}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#e6db74}.token.keyword{color:#66d9ef}.token.important,.token.regex{color:#fd971f}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
|
||||||
7
examples/assets/prism/prism.min.js
vendored
Normal file
7
examples/assets/prism/prism.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
29
examples/await/await0.html
Normal file
29
examples/await/await0.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<!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>
|
||||||
45
examples/await/await1.html
Normal file
45
examples/await/await1.html
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<!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>
|
||||||
42
examples/await/await2.html
Normal file
42
examples/await/await2.html
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<!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>
|
||||||
45
examples/await/await3.html
Normal file
45
examples/await/await3.html
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<!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>
|
||||||
39
examples/await/await4.html
Normal file
39
examples/await/await4.html
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<!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>
|
||||||
22
examples/await/await5.html
Normal file
22
examples/await/await5.html
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<!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>
|
||||||
94
examples/bokeh.html
Normal file
94
examples/bokeh.html
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
<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-3.0.3.min.js"
|
||||||
|
></script>
|
||||||
|
<script
|
||||||
|
type="text/javascript"
|
||||||
|
src="https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.0.3.min.js"
|
||||||
|
></script>
|
||||||
|
<script
|
||||||
|
type="text/javascript"
|
||||||
|
src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.0.3.min.js"
|
||||||
|
></script>
|
||||||
|
<script
|
||||||
|
type="text/javascript"
|
||||||
|
src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.0.3.min.js"
|
||||||
|
></script>
|
||||||
|
<script
|
||||||
|
type="text/javascript"
|
||||||
|
src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.0.3.min.js"
|
||||||
|
></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
Bokeh.set_log_level("info");
|
||||||
|
</script>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://pyscript.net/latest/pyscript.css"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||||
|
<style>
|
||||||
|
py-script {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script
|
||||||
|
type="module"
|
||||||
|
src="https://esm.sh/@pyscript/core@latest/core.js"
|
||||||
|
></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar" style="background-color: #000000">
|
||||||
|
<div class="app-header">
|
||||||
|
<a href="/">
|
||||||
|
<img src="./logo.png" class="logo" />
|
||||||
|
</a>
|
||||||
|
<a class="title" href="" style="color: #f0ab3c"
|
||||||
|
>Bokeh Example</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<py-tutor>
|
||||||
|
<section class="pyscript">
|
||||||
|
<div id="myplot"></div>
|
||||||
|
|
||||||
|
<py-config>
|
||||||
|
packages = [
|
||||||
|
"pandas",
|
||||||
|
"bokeh",
|
||||||
|
"xyzservices"
|
||||||
|
]
|
||||||
|
plugins = [
|
||||||
|
"https://pyscript.net/latest/plugins/python/py_tutor.py"
|
||||||
|
]
|
||||||
|
</py-config>
|
||||||
|
|
||||||
|
<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(width=400, 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>
|
||||||
|
</section>
|
||||||
|
</py-tutor>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
136
examples/bokeh_interactive.html
Normal file
136
examples/bokeh_interactive.html
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
<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.3.js"
|
||||||
|
></script>
|
||||||
|
<script
|
||||||
|
type="text/javascript"
|
||||||
|
src="https://cdn.bokeh.org/bokeh/release/bokeh-gl-2.4.3.min.js"
|
||||||
|
></script>
|
||||||
|
<script
|
||||||
|
type="text/javascript"
|
||||||
|
src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.3.min.js"
|
||||||
|
></script>
|
||||||
|
<script
|
||||||
|
type="text/javascript"
|
||||||
|
src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.3.min.js"
|
||||||
|
></script>
|
||||||
|
<script
|
||||||
|
type="text/javascript"
|
||||||
|
src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-2.4.3.min.js"
|
||||||
|
></script>
|
||||||
|
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||||
|
|
||||||
|
<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>
|
||||||
|
<nav class="navbar" style="background-color: #000000">
|
||||||
|
<div class="app-header">
|
||||||
|
<a href="/">
|
||||||
|
<img src="./logo.png" class="logo" />
|
||||||
|
</a>
|
||||||
|
<a class="title" href="" style="color: #f0ab3c"
|
||||||
|
>Bokeh Example</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<py-tutor>
|
||||||
|
<section class="pyscript">
|
||||||
|
<h1>Bokeh Example</h1>
|
||||||
|
<div id="myplot"></div>
|
||||||
|
|
||||||
|
<py-config>
|
||||||
|
packages = [
|
||||||
|
"https://cdn.holoviz.org/panel/0.14.3/dist/wheels/bokeh-2.4.3-py3-none-any.whl",
|
||||||
|
"numpy",
|
||||||
|
]
|
||||||
|
plugins = [
|
||||||
|
"https://pyscript.net/latest/plugins/python/py_tutor.py"
|
||||||
|
]
|
||||||
|
</py-config>
|
||||||
|
|
||||||
|
<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)
|
||||||
|
|
||||||
|
asyncio.ensure_future(show(row, 'myplot'))
|
||||||
|
</py-script>
|
||||||
|
</section>
|
||||||
|
</py-tutor>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
138
examples/d3.html
Normal file
138
examples/d3.html
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
<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>
|
||||||
|
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||||
|
<script src="https://d3js.org/d3.v7.min.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>
|
||||||
|
<nav class="navbar" style="background-color: #000000">
|
||||||
|
<div class="app-header">
|
||||||
|
<a href="/">
|
||||||
|
<img src="./logo.png" class="logo" />
|
||||||
|
</a>
|
||||||
|
<a class="title" href="" style="color: #f0ab3c"
|
||||||
|
>Simple d3 visualization</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<section class="pyscript">
|
||||||
|
<py-tutor modules="d3.py">
|
||||||
|
<py-config>
|
||||||
|
plugins = [
|
||||||
|
"https://pyscript.net/latest/plugins/python/py_tutor.py"
|
||||||
|
]
|
||||||
|
[[fetch]]
|
||||||
|
files = ["./d3.py"]
|
||||||
|
</py-config>
|
||||||
|
</py-tutor>
|
||||||
|
<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>
|
||||||
|
<py-script src="d3.py"></py-script>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
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>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
64
examples/d3.py
Normal file
64
examples/d3.py
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import js
|
||||||
|
from pyodide.ffi import create_proxy, to_js
|
||||||
|
|
||||||
|
d3 = js.d3
|
||||||
|
|
||||||
|
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},
|
||||||
|
]
|
||||||
|
|
||||||
|
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"])
|
||||||
|
)
|
||||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
81
examples/folium.html
Normal file
81
examples/folium.html
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<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"
|
||||||
|
/>
|
||||||
|
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||||
|
<style>
|
||||||
|
py-script {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script
|
||||||
|
type="module"
|
||||||
|
src="https://esm.sh/@pyscript/core@latest/core.js"
|
||||||
|
></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar" style="background-color: #000000">
|
||||||
|
<div class="app-header">
|
||||||
|
<a href="/">
|
||||||
|
<img src="./logo.png" class="logo" />
|
||||||
|
</a>
|
||||||
|
<a class="title" href="" style="color: #f0ab3c">Folium</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<section class="pyscript">
|
||||||
|
<div id="folium"></div>
|
||||||
|
|
||||||
|
<py-tutor>
|
||||||
|
<py-config>
|
||||||
|
packages = [
|
||||||
|
"folium",
|
||||||
|
"pandas"
|
||||||
|
]
|
||||||
|
plugins = [
|
||||||
|
"https://pyscript.net/latest/plugins/python/py_tutor.py"
|
||||||
|
]
|
||||||
|
</py-config>
|
||||||
|
|
||||||
|
<py-script>
|
||||||
|
from pyscript import display
|
||||||
|
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)
|
||||||
|
|
||||||
|
display(m, target="folium")
|
||||||
|
</py-script>
|
||||||
|
</py-tutor>
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
137
examples/handtrack/say_hello.html
Normal file
137
examples/handtrack/say_hello.html
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
|
<title>Say Hello</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, console
|
||||||
|
from pyodide import create_once_callable
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
update_note = Element("update-note")
|
||||||
|
canvas = Element("canvas")
|
||||||
|
video = Element("myvideo")
|
||||||
|
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():
|
||||||
|
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-click="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" class="updatenote mt10">loading model ..</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<video autoplay="autoplay" id="myvideo" py-mount="video"></video>
|
||||||
|
<canvas id="canvas" class="border canvasbox"></canvas>
|
||||||
|
</div>
|
||||||
|
<script src="lib/handtrack.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
55
examples/hello_world.html
Normal file
55
examples/hello_world.html
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<!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"
|
||||||
|
/>
|
||||||
|
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||||
|
<style>
|
||||||
|
py-script {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script
|
||||||
|
type="module"
|
||||||
|
src="https://esm.sh/@pyscript/core@latest/core.js"
|
||||||
|
></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav class="navbar" style="background-color: #000000">
|
||||||
|
<div class="app-header">
|
||||||
|
<a href="/">
|
||||||
|
<img src="./logo.png" class="logo" />
|
||||||
|
</a>
|
||||||
|
<a class="title" href="" style="color: #f0ab3c">Hello World</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<py-tutor>
|
||||||
|
<py-config>
|
||||||
|
plugins = [
|
||||||
|
"https://pyscript.net/latest/plugins/python/py_tutor.py"
|
||||||
|
]
|
||||||
|
</py-config>
|
||||||
|
|
||||||
|
<section class="pyscript">
|
||||||
|
Hello world! <br />
|
||||||
|
This is the current date and time, as computed by Python:
|
||||||
|
<py-script>
|
||||||
|
from pyscript import display
|
||||||
|
from datetime import datetime
|
||||||
|
now = datetime.now()
|
||||||
|
display(now.strftime("%m/%d/%Y, %H:%M:%S"))
|
||||||
|
</py-script>
|
||||||
|
</section>
|
||||||
|
</py-tutor>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
315
examples/index.html
Normal file
315
examples/index.html
Normal file
@@ -0,0 +1,315 @@
|
|||||||
|
<!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 the
|
||||||
|
<code><py-script></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="./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>
|
||||||
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
35
examples/mario/css/game.css
Normal file
35
examples/mario/css/game.css
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
43
examples/mario/js/bcoin.js
Normal file
43
examples/mario/js/bcoin.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
(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 () {};
|
||||||
|
})();
|
||||||
84
examples/mario/js/block.js
Normal file
84
examples/mario/js/block.js
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
(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);
|
||||||
|
};
|
||||||
|
})();
|
||||||
62
examples/mario/js/coin.js
Normal file
62
examples/mario/js/coin.js
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
(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];
|
||||||
|
};
|
||||||
|
})();
|
||||||
34
examples/mario/js/entity.js
Normal file
34
examples/mario/js/entity.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
(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 () {};
|
||||||
|
})();
|
||||||
145
examples/mario/js/fireball.js
Normal file
145
examples/mario/js/fireball.js
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
(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 () {};
|
||||||
|
})();
|
||||||
90
examples/mario/js/fireflower.js
Normal file
90
examples/mario/js/fireflower.js
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
(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] = -0.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 () {};
|
||||||
|
})();
|
||||||
51
examples/mario/js/flag.js
Normal file
51
examples/mario/js/flag.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
(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,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
})();
|
||||||
83
examples/mario/js/floor.js
Normal file
83
examples/mario/js/floor.js
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
(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 () {};
|
||||||
|
})();
|
||||||
253
examples/mario/js/game.js
Normal file
253
examples/mario/js/game.js
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
147
examples/mario/js/goomba.js
Normal file
147
examples/mario/js/goomba.js
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
(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;
|
||||||
|
};
|
||||||
|
})();
|
||||||
61
examples/mario/js/input.js
Normal file
61
examples/mario/js/input.js
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
(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;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
})();
|
||||||
228
examples/mario/js/koopa.js
Normal file
228
examples/mario/js/koopa.js
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
(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;
|
||||||
|
};
|
||||||
|
})();
|
||||||
341
examples/mario/js/levels/11.js
Normal file
341
examples/mario/js/levels/11.js
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
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();
|
||||||
|
});
|
||||||
138
examples/mario/js/levels/11tunnel.js
Normal file
138
examples/mario/js/levels/11tunnel.js
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
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();
|
||||||
|
});
|
||||||
348
examples/mario/js/levels/level.js
Normal file
348
examples/mario/js/levels/level.js
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
(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));
|
||||||
|
};
|
||||||
|
})();
|
||||||
132
examples/mario/js/mushroom.js
Normal file
132
examples/mario/js/mushroom.js
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
(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] = -0.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;
|
||||||
|
};
|
||||||
|
})();
|
||||||
228
examples/mario/js/pipe.js
Normal file
228
examples/mario/js/pipe.js
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
(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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
505
examples/mario/js/player.js
Normal file
505
examples/mario/js/player.js
Normal file
@@ -0,0 +1,505 @@
|
|||||||
|
(function () {
|
||||||
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
|
|
||||||
|
var Player = (Mario.Player = function (pos) {
|
||||||
|
//I know, I know, there are a lot of variables tracking Mario's state.
|
||||||
|
//Maybe these can be consolidated some way? We'll see once they're all in.
|
||||||
|
this.power = 0;
|
||||||
|
this.coins = 0;
|
||||||
|
this.powering = [];
|
||||||
|
this.bounce = false;
|
||||||
|
this.jumping = 0;
|
||||||
|
this.canJump = true;
|
||||||
|
this.invincibility = 0;
|
||||||
|
this.crouching = false;
|
||||||
|
this.fireballs = 0;
|
||||||
|
this.runheld = false;
|
||||||
|
this.noInput = false;
|
||||||
|
this.targetPos = [];
|
||||||
|
|
||||||
|
Mario.Entity.call(this, {
|
||||||
|
pos: pos,
|
||||||
|
sprite: new Mario.Sprite(
|
||||||
|
"sprites/player.png",
|
||||||
|
[80, 32],
|
||||||
|
[16, 16],
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
hitbox: [0, 0, 16, 16],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Mario.Util.inherits(Player, Mario.Entity);
|
||||||
|
|
||||||
|
Player.prototype.run = function () {
|
||||||
|
this.maxSpeed = 2.5;
|
||||||
|
if (this.power == 2 && !this.runheld) {
|
||||||
|
this.shoot();
|
||||||
|
}
|
||||||
|
this.runheld = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.shoot = function () {
|
||||||
|
if (this.fireballs >= 2) return; //Projectile limit!
|
||||||
|
this.fireballs += 1;
|
||||||
|
var fb = new Mario.Fireball([this.pos[0] + 8, this.pos[1]]); //I hate you, Javascript.
|
||||||
|
fb.spawn(this.left);
|
||||||
|
this.shooting = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.noRun = function () {
|
||||||
|
this.maxSpeed = 1.5;
|
||||||
|
this.moveAcc = 0.07;
|
||||||
|
this.runheld = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.moveRight = function () {
|
||||||
|
//we're on the ground
|
||||||
|
if (this.vel[1] === 0 && this.standing) {
|
||||||
|
if (this.crouching) {
|
||||||
|
this.noWalk();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.acc[0] = this.moveAcc;
|
||||||
|
this.left = false;
|
||||||
|
} else {
|
||||||
|
this.acc[0] = this.moveAcc;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.moveLeft = function () {
|
||||||
|
if (this.vel[1] === 0 && this.standing) {
|
||||||
|
if (this.crouching) {
|
||||||
|
this.noWalk();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.acc[0] = -this.moveAcc;
|
||||||
|
this.left = true;
|
||||||
|
} else {
|
||||||
|
this.acc[0] = -this.moveAcc;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.noWalk = function () {
|
||||||
|
this.maxSpeed = 0;
|
||||||
|
if (this.vel[0] === 0) return;
|
||||||
|
|
||||||
|
if (Math.abs(this.vel[0]) <= 0.1) {
|
||||||
|
this.vel[0] = 0;
|
||||||
|
this.acc[0] = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.crouch = function () {
|
||||||
|
if (this.power === 0) {
|
||||||
|
this.crouching = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.standing) this.crouching = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.noCrouch = function () {
|
||||||
|
this.crouching = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.jump = function () {
|
||||||
|
if (this.vel[1] > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.jumping) {
|
||||||
|
this.jumping -= 1;
|
||||||
|
} else if (this.standing && this.canJump) {
|
||||||
|
this.jumping = 20;
|
||||||
|
this.canJump = false;
|
||||||
|
this.standing = false;
|
||||||
|
this.vel[1] = -6;
|
||||||
|
if (this.power === 0) {
|
||||||
|
sounds.smallJump.currentTime = 0;
|
||||||
|
sounds.smallJump.play();
|
||||||
|
} else {
|
||||||
|
sounds.bigJump.currentTime = 0;
|
||||||
|
sounds.bigJump.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.noJump = function () {
|
||||||
|
this.canJump = true;
|
||||||
|
if (this.jumping) {
|
||||||
|
if (this.jumping <= 16) {
|
||||||
|
this.vel[1] = 0;
|
||||||
|
this.jumping = 0;
|
||||||
|
} else this.jumping -= 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.setAnimation = function () {
|
||||||
|
if (this.dying) return;
|
||||||
|
|
||||||
|
if (this.starTime) {
|
||||||
|
var index;
|
||||||
|
if (this.starTime > 60) index = Math.floor(this.starTime / 2) % 3;
|
||||||
|
else index = Math.floor(this.starTime / 8) % 3;
|
||||||
|
|
||||||
|
this.sprite.pos[1] = level.invincibility[index];
|
||||||
|
if (this.power == 0) {
|
||||||
|
this.sprite.pos[1] += 32;
|
||||||
|
}
|
||||||
|
this.starTime -= 1;
|
||||||
|
if (this.starTime == 0) {
|
||||||
|
switch (this.power) {
|
||||||
|
case 0:
|
||||||
|
this.sprite.pos[1] = 32;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
this.sprite.pos[1] = 0;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
this.sprite.pos[1] = 96;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//okay cool, now set the sprite
|
||||||
|
if (this.crouching) {
|
||||||
|
this.sprite.pos[0] = 176;
|
||||||
|
this.sprite.speed = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.jumping) {
|
||||||
|
this.sprite.pos[0] = 160;
|
||||||
|
this.sprite.speed = 0;
|
||||||
|
} else if (this.standing) {
|
||||||
|
if (Math.abs(this.vel[0]) > 0) {
|
||||||
|
if (this.vel[0] * this.acc[0] >= 0) {
|
||||||
|
this.sprite.pos[0] = 96;
|
||||||
|
this.sprite.frames = [0, 1, 2];
|
||||||
|
if (this.vel[0] < 0.2) {
|
||||||
|
this.sprite.speed = 5;
|
||||||
|
} else {
|
||||||
|
this.sprite.speed = Math.abs(this.vel[0]) * 8;
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
(this.vel[0] > 0 && this.left) ||
|
||||||
|
(this.vel[0] < 0 && !this.left)
|
||||||
|
) {
|
||||||
|
this.sprite.pos[0] = 144;
|
||||||
|
this.sprite.speed = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.sprite.pos[0] = 80;
|
||||||
|
this.sprite.speed = 0;
|
||||||
|
}
|
||||||
|
if (this.shooting) {
|
||||||
|
this.sprite.pos[0] += 160;
|
||||||
|
this.shooting -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.flagging) {
|
||||||
|
this.sprite.pos[0] = 192;
|
||||||
|
this.sprite.frames = [0, 1];
|
||||||
|
this.sprite.speed = 10;
|
||||||
|
if (this.vel[1] === 0) this.sprite.frames = [0];
|
||||||
|
}
|
||||||
|
|
||||||
|
//which way are we facing?
|
||||||
|
if (this.left) {
|
||||||
|
this.sprite.img = "sprites/playerl.png";
|
||||||
|
} else {
|
||||||
|
this.sprite.img = "sprites/player.png";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.update = function (dt, vX) {
|
||||||
|
if (this.powering.length !== 0) {
|
||||||
|
var next = this.powering.shift();
|
||||||
|
if (next == 5) return;
|
||||||
|
this.sprite.pos = this.powerSprites[next];
|
||||||
|
this.sprite.size = this.powerSizes[next];
|
||||||
|
this.pos[1] += this.shift[next];
|
||||||
|
if (this.powering.length === 0) {
|
||||||
|
delete level.items[this.touchedItem];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.invincibility) {
|
||||||
|
this.invincibility -= Math.round(dt * 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.waiting) {
|
||||||
|
this.waiting -= dt;
|
||||||
|
if (this.waiting <= 0) {
|
||||||
|
this.waiting = 0;
|
||||||
|
} else return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.bounce) {
|
||||||
|
this.bounce = false;
|
||||||
|
this.standing = false;
|
||||||
|
this.vel[1] = -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.pos[0] <= vX) {
|
||||||
|
this.pos[0] = vX;
|
||||||
|
this.vel[0] = Math.max(this.vel[0], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.abs(this.vel[0]) > this.maxSpeed) {
|
||||||
|
this.vel[0] -= (0.05 * this.vel[0]) / Math.abs(this.vel[0]);
|
||||||
|
this.acc[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.dying) {
|
||||||
|
if (this.pos[1] < this.targetPos[1]) {
|
||||||
|
this.vel[1] = 1;
|
||||||
|
}
|
||||||
|
this.dying -= 1 * dt;
|
||||||
|
if (this.dying <= 0) {
|
||||||
|
player = new Mario.Player(level.playerPos);
|
||||||
|
level.loader.call();
|
||||||
|
input.reset();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.acc[1] = 0.25;
|
||||||
|
if (this.pos[1] > 240) {
|
||||||
|
this.die();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.piping) {
|
||||||
|
this.acc = [0, 0];
|
||||||
|
var pos = [Math.round(this.pos[0]), Math.round(this.pos[1])];
|
||||||
|
if (pos[0] === this.targetPos[0] && pos[1] === this.targetPos[1]) {
|
||||||
|
this.piping = false;
|
||||||
|
this.pipeLoc.call();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.flagging) {
|
||||||
|
this.acc = [0, 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.exiting) {
|
||||||
|
this.left = false;
|
||||||
|
this.flagging = false;
|
||||||
|
this.vel[0] = 1.5;
|
||||||
|
if (this.pos[0] >= this.targetPos[0]) {
|
||||||
|
this.sprite.size = [0, 0];
|
||||||
|
this.vel = [0, 0];
|
||||||
|
window.setTimeout(function () {
|
||||||
|
player.sprite.size =
|
||||||
|
player.power === 0 ? [16, 16] : [16, 32];
|
||||||
|
player.exiting = false;
|
||||||
|
player.noInput = false;
|
||||||
|
level.loader();
|
||||||
|
if (player.power !== 0) player.pos[1] -= 16;
|
||||||
|
music.overworld.currentTime = 0;
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//approximate acceleration
|
||||||
|
this.vel[0] += this.acc[0];
|
||||||
|
this.vel[1] += this.acc[1];
|
||||||
|
this.pos[0] += this.vel[0];
|
||||||
|
this.pos[1] += this.vel[1];
|
||||||
|
|
||||||
|
this.setAnimation();
|
||||||
|
this.sprite.update(dt);
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.checkCollisions = function () {
|
||||||
|
if (this.piping || this.dying) return;
|
||||||
|
//x-axis first!
|
||||||
|
var h = this.power > 0 ? 2 : 1;
|
||||||
|
var w = 1;
|
||||||
|
if (this.pos[1] % 16 !== 0) {
|
||||||
|
h += 1;
|
||||||
|
}
|
||||||
|
if (this.pos[0] % 16 !== 0) {
|
||||||
|
w += 1;
|
||||||
|
}
|
||||||
|
var baseX = Math.floor(this.pos[0] / 16);
|
||||||
|
var baseY = Math.floor(this.pos[1] / 16);
|
||||||
|
|
||||||
|
for (var i = 0; i < h; i++) {
|
||||||
|
if (baseY + i < 0 || baseY + i >= 15) continue;
|
||||||
|
for (var j = 0; j < w; j++) {
|
||||||
|
if (baseY < 0) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.powerUp = function (idx) {
|
||||||
|
sounds.powerup.play();
|
||||||
|
this.powering = [
|
||||||
|
0, 5, 2, 5, 1, 5, 2, 5, 1, 5, 2, 5, 3, 5, 1, 5, 2, 5, 3, 5, 1, 5, 4,
|
||||||
|
];
|
||||||
|
this.touchedItem = idx;
|
||||||
|
|
||||||
|
if (this.power === 0) {
|
||||||
|
this.sprite.pos[0] = 80;
|
||||||
|
var newy = this.sprite.pos[1] - 32;
|
||||||
|
this.powerSprites = [
|
||||||
|
[80, newy + 32],
|
||||||
|
[80, newy + 32],
|
||||||
|
[320, newy],
|
||||||
|
[80, newy],
|
||||||
|
[128, newy],
|
||||||
|
];
|
||||||
|
this.powerSizes = [
|
||||||
|
[16, 16],
|
||||||
|
[16, 16],
|
||||||
|
[16, 32],
|
||||||
|
[16, 32],
|
||||||
|
[16, 32],
|
||||||
|
];
|
||||||
|
this.shift = [0, 16, -16, 0, -16];
|
||||||
|
this.power = 1;
|
||||||
|
this.hitbox = [0, 0, 16, 32];
|
||||||
|
} else if (this.power == 1) {
|
||||||
|
var curx = this.sprite.pos[0];
|
||||||
|
this.powerSprites = [
|
||||||
|
[curx, 96],
|
||||||
|
[curx, level.invincibility[0]],
|
||||||
|
[curx, level.invincibility[1]],
|
||||||
|
[curx, level.invincibility[2]],
|
||||||
|
[curx, 96],
|
||||||
|
];
|
||||||
|
this.powerSizes[([16, 32], [16, 32], [16, 32], [16, 32], [16, 32])];
|
||||||
|
this.shift = [0, 0, 0, 0, 0];
|
||||||
|
this.power = 2;
|
||||||
|
} else {
|
||||||
|
this.powering = [];
|
||||||
|
delete level.items[idx];
|
||||||
|
//no animation, but we play the sound and you get 5000 points.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.damage = function () {
|
||||||
|
if (this.power === 0) {
|
||||||
|
//if you're already small, you dead!
|
||||||
|
this.die();
|
||||||
|
} else {
|
||||||
|
//otherwise, you get turned into small mario
|
||||||
|
sounds.pipe.play();
|
||||||
|
this.powering = [
|
||||||
|
0, 5, 1, 5, 2, 5, 1, 5, 2, 5, 1, 5, 2, 5, 1, 5, 2, 5, 1, 5, 2,
|
||||||
|
5, 3,
|
||||||
|
];
|
||||||
|
this.shift = [0, 16, -16, 16];
|
||||||
|
this.sprite.pos = [160, 0];
|
||||||
|
this.powerSprites = [
|
||||||
|
[160, 0],
|
||||||
|
[240, 32],
|
||||||
|
[240, 0],
|
||||||
|
[160, 32],
|
||||||
|
];
|
||||||
|
this.powerSizes = [
|
||||||
|
[16, 32],
|
||||||
|
[16, 16],
|
||||||
|
[16, 32],
|
||||||
|
[16, 16],
|
||||||
|
];
|
||||||
|
this.invincibility = 120;
|
||||||
|
this.power = 0;
|
||||||
|
this.hitbox = [0, 0, 16, 16];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.die = function () {
|
||||||
|
//TODO: rewrite the way sounds work to emulate the channels of an NES.
|
||||||
|
music.overworld.pause();
|
||||||
|
music.underground.pause();
|
||||||
|
music.overworld.currentTime = 0;
|
||||||
|
music.death.play();
|
||||||
|
this.noWalk();
|
||||||
|
this.noRun();
|
||||||
|
this.noJump();
|
||||||
|
|
||||||
|
this.acc[0] = 0;
|
||||||
|
this.sprite.pos = [176, 32];
|
||||||
|
this.sprite.speed = 0;
|
||||||
|
this.power = 0;
|
||||||
|
this.waiting = 0.5;
|
||||||
|
this.dying = 2;
|
||||||
|
|
||||||
|
if (this.pos[1] < 240) {
|
||||||
|
//falling into a pit doesn't do the animation.
|
||||||
|
this.targetPos = [this.pos[0], this.pos[1] - 128];
|
||||||
|
this.vel = [0, -5];
|
||||||
|
} else {
|
||||||
|
this.vel = [0, 0];
|
||||||
|
this.targetPos = [this.pos[0], this.pos[1] - 16];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.star = function (idx) {
|
||||||
|
delete level.items[idx];
|
||||||
|
this.starTime = 660;
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.pipe = function (direction, destination) {
|
||||||
|
sounds.pipe.play();
|
||||||
|
this.piping = true;
|
||||||
|
this.pipeLoc = destination;
|
||||||
|
switch (direction) {
|
||||||
|
case "LEFT":
|
||||||
|
this.vel = [-1, 0];
|
||||||
|
this.targetPos = [
|
||||||
|
Math.round(this.pos[0] - 16),
|
||||||
|
Math.round(this.pos[1]),
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
case "RIGHT":
|
||||||
|
this.vel = [1, 0];
|
||||||
|
this.targetPos = [
|
||||||
|
Math.round(this.pos[0] + 16),
|
||||||
|
Math.round(this.pos[1]),
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
case "DOWN":
|
||||||
|
this.vel = [0, 1];
|
||||||
|
this.targetPos = [
|
||||||
|
Math.round(this.pos[0]),
|
||||||
|
Math.round(this.pos[1] + this.hitbox[3]),
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
case "UP":
|
||||||
|
this.vel = [0, -1];
|
||||||
|
this.targetPos = [
|
||||||
|
Math.round(this.pos[0]),
|
||||||
|
Math.round(this.pos[1] - this.hitbox[3]),
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.flag = function () {
|
||||||
|
this.noInput = true;
|
||||||
|
this.flagging = true;
|
||||||
|
this.vel = [0, 2];
|
||||||
|
this.acc = [0, 0];
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.exit = function () {
|
||||||
|
this.pos[0] += 16;
|
||||||
|
this.targetPos[0] = level.exit * 16;
|
||||||
|
this.left = true;
|
||||||
|
this.setAnimation();
|
||||||
|
this.waiting = 1;
|
||||||
|
this.exiting = true;
|
||||||
|
};
|
||||||
|
})();
|
||||||
14
examples/mario/js/prop.js
Normal file
14
examples/mario/js/prop.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
(function () {
|
||||||
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
|
|
||||||
|
//props do even less than entities, so they don't need to inherit really
|
||||||
|
var Prop = (Mario.Prop = function (pos, sprite) {
|
||||||
|
this.pos = pos;
|
||||||
|
this.sprite = sprite;
|
||||||
|
});
|
||||||
|
|
||||||
|
//but we will be using the same Render, more or less.
|
||||||
|
Prop.prototype.render = function (ctx, vX, vY) {
|
||||||
|
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||||
|
};
|
||||||
|
})();
|
||||||
@@ -1,32 +1,32 @@
|
|||||||
//simple resource loader
|
//simple resource loader
|
||||||
(function() {
|
(function () {
|
||||||
var resourceCache = {};
|
var resourceCache = {};
|
||||||
var loading = [];
|
var loading = [];
|
||||||
var readyCallbacks = [];
|
var readyCallbacks = [];
|
||||||
|
|
||||||
// Load an image url or an array of image urls
|
// Load an image url or an array of image urls
|
||||||
function load(urlOrArr) {
|
function load(urlOrArr) {
|
||||||
if(urlOrArr instanceof Array) {
|
if (urlOrArr instanceof Array) {
|
||||||
urlOrArr.forEach(function(url) {
|
urlOrArr.forEach(function (url) {
|
||||||
_load(url);
|
_load(url);
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
_load(urlOrArr);
|
_load(urlOrArr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _load(url) {
|
function _load(url) {
|
||||||
if(resourceCache[url]) {
|
if (resourceCache[url]) {
|
||||||
return resourceCache[url];
|
return resourceCache[url];
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
var img = new Image();
|
var img = new Image();
|
||||||
img.onload = function() {
|
img.onload = function () {
|
||||||
resourceCache[url] = img;
|
resourceCache[url] = img;
|
||||||
|
|
||||||
if(isReady()) {
|
if (isReady()) {
|
||||||
readyCallbacks.forEach(function(func) { func(); });
|
readyCallbacks.forEach(function (func) {
|
||||||
|
func();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
resourceCache[url] = false;
|
resourceCache[url] = false;
|
||||||
@@ -40,9 +40,8 @@
|
|||||||
|
|
||||||
function isReady() {
|
function isReady() {
|
||||||
var ready = true;
|
var ready = true;
|
||||||
for(var k in resourceCache) {
|
for (var k in resourceCache) {
|
||||||
if(resourceCache.hasOwnProperty(k) &&
|
if (resourceCache.hasOwnProperty(k) && !resourceCache[k]) {
|
||||||
!resourceCache[k]) {
|
|
||||||
ready = false;
|
ready = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,6 +56,6 @@
|
|||||||
load: load,
|
load: load,
|
||||||
get: get,
|
get: get,
|
||||||
onReady: onReady,
|
onReady: onReady,
|
||||||
isReady: isReady
|
isReady: isReady,
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
64
examples/mario/js/rubble.js
Normal file
64
examples/mario/js/rubble.js
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
(function () {
|
||||||
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
|
|
||||||
|
//TODO: make each rubble an entity, use that render and write in Entity.update
|
||||||
|
var Rubble = (Mario.Rubble = function () {
|
||||||
|
this.sprites = [];
|
||||||
|
this.poss = [];
|
||||||
|
this.vels = [];
|
||||||
|
});
|
||||||
|
|
||||||
|
Rubble.prototype.spawn = function (pos) {
|
||||||
|
this.idx = level.items.length;
|
||||||
|
level.items.push(this);
|
||||||
|
this.sprites[0] = level.rubbleSprite();
|
||||||
|
this.sprites[1] = level.rubbleSprite();
|
||||||
|
this.sprites[2] = level.rubbleSprite();
|
||||||
|
this.sprites[3] = level.rubbleSprite();
|
||||||
|
this.poss[0] = pos;
|
||||||
|
this.poss[1] = [pos[0] + 8, pos[1]];
|
||||||
|
this.poss[2] = [pos[0], pos[1] + 8];
|
||||||
|
this.poss[3] = [pos[0] + 8, pos[1] + 8];
|
||||||
|
this.vels[0] = [-1.25, -5];
|
||||||
|
this.vels[1] = [1.25, -5];
|
||||||
|
this.vels[2] = [-1.25, -3];
|
||||||
|
this.vels[3] = [1.25, -3];
|
||||||
|
};
|
||||||
|
|
||||||
|
Rubble.prototype.update = function (dt) {
|
||||||
|
for (var i = 0; i < 4; i++) {
|
||||||
|
if (this.sprites[i] === undefined) continue;
|
||||||
|
this.vels[i][1] += 0.3;
|
||||||
|
this.poss[i][0] += this.vels[i][0];
|
||||||
|
this.poss[i][1] += this.vels[i][1];
|
||||||
|
this.sprites[i].update(dt);
|
||||||
|
if (this.poss[i][1] > 256) {
|
||||||
|
delete this.sprites[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
this.sprites.every(function (el) {
|
||||||
|
return !el;
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
delete level.items[this.idx];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//You might argue that things that can't collide are more like scenery
|
||||||
|
//but these move and need to be deleted, and i'd rather deal with the 1d array.
|
||||||
|
Rubble.prototype.checkCollisions = function () {};
|
||||||
|
|
||||||
|
Rubble.prototype.render = function () {
|
||||||
|
for (var i = 0; i < 4; i++) {
|
||||||
|
if (this.sprites[i] === undefined) continue;
|
||||||
|
this.sprites[i].render(
|
||||||
|
ctx,
|
||||||
|
this.poss[i][0],
|
||||||
|
this.poss[i][1],
|
||||||
|
vX,
|
||||||
|
vY,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
63
examples/mario/js/sprite.js
Normal file
63
examples/mario/js/sprite.js
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
(function () {
|
||||||
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
|
|
||||||
|
var Sprite = (Mario.Sprite = function (
|
||||||
|
img,
|
||||||
|
pos,
|
||||||
|
size,
|
||||||
|
speed,
|
||||||
|
frames,
|
||||||
|
once,
|
||||||
|
) {
|
||||||
|
this.pos = pos;
|
||||||
|
this.size = size;
|
||||||
|
this.speed = speed;
|
||||||
|
this._index = 0;
|
||||||
|
this.img = img;
|
||||||
|
this.once = once;
|
||||||
|
this.frames = frames;
|
||||||
|
});
|
||||||
|
|
||||||
|
Sprite.prototype.update = function (dt, gameTime) {
|
||||||
|
if (gameTime && gameTime == this.lastUpdated) return;
|
||||||
|
this._index += this.speed * dt;
|
||||||
|
if (gameTime) this.lastUpdated = gameTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
Sprite.prototype.setFrame = function (frame) {
|
||||||
|
this._index = frame;
|
||||||
|
};
|
||||||
|
|
||||||
|
Sprite.prototype.render = function (ctx, posx, posy, vX, vY) {
|
||||||
|
var frame;
|
||||||
|
|
||||||
|
if (this.speed > 0) {
|
||||||
|
var max = this.frames.length;
|
||||||
|
var idx = Math.floor(this._index);
|
||||||
|
frame = this.frames[idx % max];
|
||||||
|
|
||||||
|
if (this.once && idx >= max) {
|
||||||
|
this.done = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
frame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var x = this.pos[0];
|
||||||
|
var y = this.pos[1];
|
||||||
|
|
||||||
|
x += frame * this.size[0];
|
||||||
|
ctx.drawImage(
|
||||||
|
resources.get(this.img),
|
||||||
|
x + 1 / 3,
|
||||||
|
y + 1 / 3,
|
||||||
|
this.size[0] - 2 / 3,
|
||||||
|
this.size[1] - 2 / 3,
|
||||||
|
Math.round(posx - vX),
|
||||||
|
Math.round(posy - vY),
|
||||||
|
this.size[0],
|
||||||
|
this.size[1],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
})();
|
||||||
130
examples/mario/js/star.js
Normal file
130
examples/mario/js/star.js
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
(function () {
|
||||||
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
|
|
||||||
|
var Star = (Mario.Star = function (pos) {
|
||||||
|
this.spawning = false;
|
||||||
|
this.waiting = 0;
|
||||||
|
|
||||||
|
Mario.Entity.call(this, {
|
||||||
|
pos: pos,
|
||||||
|
sprite: level.starSprite,
|
||||||
|
hitbox: [0, 0, 16, 16],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Mario.Util.inherits(Star, Mario.Entity);
|
||||||
|
|
||||||
|
Star.prototype.render = function (ctx, vX, vY) {
|
||||||
|
if (this.spawning > 1) return;
|
||||||
|
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||||
|
};
|
||||||
|
|
||||||
|
Star.prototype.spawn = function () {
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
Star.prototype.update = function (dt) {
|
||||||
|
if (this.spawning > 1) {
|
||||||
|
this.spawning -= 1;
|
||||||
|
if (this.spawning == 1) this.vel[1] = -0.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.standing) {
|
||||||
|
this.standing = false;
|
||||||
|
this.vel[1] = -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Star.prototype.collideWall = function () {
|
||||||
|
this.vel[0] = -this.vel[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
Star.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.
|
||||||
|
Star.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.star(this.idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Star.prototype.bump = function () {
|
||||||
|
this.vel[1] = -2;
|
||||||
|
};
|
||||||
|
})();
|
||||||
14
examples/mario/js/util.js
Normal file
14
examples/mario/js/util.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
(function () {
|
||||||
|
if (typeof Mario === "undefined") {
|
||||||
|
window.Mario = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
var Util = (Mario.Util = {});
|
||||||
|
|
||||||
|
Util.inherits = function (subclass, superclass) {
|
||||||
|
function Surrogate() {}
|
||||||
|
|
||||||
|
Surrogate.prototype = superclass.prototype;
|
||||||
|
subclass.prototype = new Surrogate();
|
||||||
|
};
|
||||||
|
})();
|
||||||
160
examples/mario/play_mario.html
Normal file
160
examples/mario/play_mario.html
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
|
<title>Mario</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>
|
||||||
|
<script type="text/javascript" src="js/util.js"></script>
|
||||||
|
<script type="text/javascript" src="js/input.js"></script>
|
||||||
|
<script type="text/javascript" src="js/resources.js"></script>
|
||||||
|
<script type="text/javascript" src="js/sprite.js"></script>
|
||||||
|
<script type="text/javascript" src="js/entity.js"></script>
|
||||||
|
<script type="text/javascript" src="js/pipe.js"></script>
|
||||||
|
<script type="text/javascript" src="js/mushroom.js"></script>
|
||||||
|
<script type="text/javascript" src="js/fireflower.js"></script>
|
||||||
|
<script type="text/javascript" src="js/star.js"></script>
|
||||||
|
<script type="text/javascript" src="js/fireball.js"></script>
|
||||||
|
<script type="text/javascript" src="js/coin.js"></script>
|
||||||
|
<script type="text/javascript" src="js/bcoin.js"></script>
|
||||||
|
<script type="text/javascript" src="js/goomba.js"></script>
|
||||||
|
<script type="text/javascript" src="js/koopa.js"></script>
|
||||||
|
<script type="text/javascript" src="js/floor.js"></script>
|
||||||
|
<script type="text/javascript" src="js/block.js"></script>
|
||||||
|
<script type="text/javascript" src="js/rubble.js"></script>
|
||||||
|
<script type="text/javascript" src="js/prop.js"></script>
|
||||||
|
<script type="text/javascript" src="js/player.js"></script>
|
||||||
|
<script type="text/javascript" src="js/flag.js"></script>
|
||||||
|
<script type="text/javascript" src="js/levels/level.js"></script>
|
||||||
|
<script type="text/javascript" src="js/levels/11.js"></script>
|
||||||
|
<script type="text/javascript" src="js/levels/11tunnel.js"></script>
|
||||||
|
<script type="text/javascript" src="js/game.js"></script>
|
||||||
|
|
||||||
|
<py-script>
|
||||||
|
from js import handTrack, setTimeout, requestAnimationFrame, player
|
||||||
|
from pyodide import create_once_callable
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
update_note = Element("update-note")
|
||||||
|
canvas = Element("canvas")
|
||||||
|
video = Element("myvideo")
|
||||||
|
context = canvas.element.getContext("2d")
|
||||||
|
|
||||||
|
isVideo = False
|
||||||
|
model = None
|
||||||
|
last_position = 0
|
||||||
|
direction = "stop"
|
||||||
|
|
||||||
|
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():
|
||||||
|
global isVideo
|
||||||
|
player.jump()
|
||||||
|
|
||||||
|
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 start 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():
|
||||||
|
global model
|
||||||
|
global isVideo
|
||||||
|
global last_position
|
||||||
|
global direction
|
||||||
|
|
||||||
|
predictions = await model.detect(video.element)
|
||||||
|
model.renderPredictions(predictions, canvas.element, context, video.element);
|
||||||
|
|
||||||
|
if predictions:
|
||||||
|
curr_position = predictions[0].bbox[0] + (predictions[0].bbox[2] / 2)
|
||||||
|
delta = last_position - curr_position
|
||||||
|
last_position = curr_position
|
||||||
|
#console.log(delta, curr_position, last_position)
|
||||||
|
if abs(delta) < 2:
|
||||||
|
direction = "stop"
|
||||||
|
elif delta > 0:
|
||||||
|
direction = "left"
|
||||||
|
else:
|
||||||
|
direction = "right"
|
||||||
|
|
||||||
|
for prediction in predictions:
|
||||||
|
if prediction.label == 'open':
|
||||||
|
player.jump()
|
||||||
|
elif prediction.label == 'close':
|
||||||
|
player.crouch()
|
||||||
|
|
||||||
|
if (isVideo):
|
||||||
|
await requestAnimationFrame(create_once_callable(sync_run_detection));
|
||||||
|
|
||||||
|
def handle_model(lmodel):
|
||||||
|
global model
|
||||||
|
model = lmodel
|
||||||
|
update_note.write("Loaded Model!")
|
||||||
|
|
||||||
|
async def start():
|
||||||
|
model = await handTrack.load(modelParams)#.then(handle_model)
|
||||||
|
handle_model(model)
|
||||||
|
|
||||||
|
pyscript.run_until_complete(start())
|
||||||
|
</py-script>
|
||||||
|
|
||||||
|
<div class="mb10">
|
||||||
|
<p>
|
||||||
|
Use < > to move, ↓ to crouch and x to jump. If video is enabled,
|
||||||
|
say hi to jump as well!
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
id="trackbutton"
|
||||||
|
class="bx--btn bx--btn--secondary"
|
||||||
|
type="button"
|
||||||
|
py-click="toggle_video()"
|
||||||
|
>
|
||||||
|
Start Video
|
||||||
|
</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="../handtrack/lib/handtrack.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user