More automatically generated formatter changes (#1254)

Apparently some of these were accidentally lost when generating #1210...
This commit is contained in:
Hood Chatham
2023-03-06 16:06:30 +01:00
committed by GitHub
parent 08f34f748b
commit 22fd023635
76 changed files with 6311 additions and 5943 deletions

View File

@@ -7,7 +7,7 @@ on:
paths:
- pyscriptjs/**
- examples/**
- .github/workflows/build-latest.yml # Test that workflow works when changed
- .github/workflows/build-latest.yml # Test that workflow works when changed
pull_request: # Run on any PR that modifies files under pyscriptjs/ and examples/
branches:
@@ -15,7 +15,7 @@ on:
paths:
- pyscriptjs/**
- examples/**
- .github/workflows/build-unstable.yml # Test that workflow works when changed
- .github/workflows/build-unstable.yml # Test that workflow works when changed
workflow_dispatch:
jobs:
@@ -41,7 +41,7 @@ jobs:
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
# 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: |
@@ -96,7 +96,7 @@ jobs:
name: pyscript
path: ./build/
# Deploy to S3
# Deploy to S3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1.6.1
with:

View File

@@ -16,8 +16,8 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
with:
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
- name: Setup
uses: conda-incubator/setup-miniconda@v2
@@ -39,7 +39,7 @@ jobs:
name: pyscript-docs-${{ github.ref_name }}
path: docs/_build/html/
# Deploy to S3
# Deploy to S3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1.6.1
with:
@@ -52,11 +52,11 @@ jobs:
- name: Sync to S3
run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/${{ github.ref_name }}/
# Make sure to remove the latest folder so we sync the full docs upon release
# Make sure to remove the latest folder so we sync the full docs upon release
- name: Delete latest directory
run: aws s3 rm --recursive s3://docs.pyscript.net/latest/
# Note that the files are the same as above, but we want to have folders with
# /<tag name>/ AND /latest/ which latest will always point to the latest release
# Note that the files are the same as above, but we want to have folders with
# /<tag name>/ AND /latest/ which latest will always point to the latest release
- name: Sync to /latest
run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/latest/

View File

@@ -8,11 +8,11 @@ on:
- docs/**
concurrency:
# Concurrency group that uses the workflow name and PR number if available
# or commit SHA as a fallback. If a new build is triggered under that
# concurrency group while a previous build is running it will be canceled.
# Repeated pushes to a PR will cancel all previous builds, while multiple
# merges to main will not cancel.
# Concurrency group that uses the workflow name and PR number if available
# or commit SHA as a fallback. If a new build is triggered under that
# concurrency group while a previous build is running it will be canceled.
# Repeated pushes to a PR will cancel all previous builds, while multiple
# merges to main will not cancel.
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
@@ -29,8 +29,8 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
with:
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
- name: Setup
uses: conda-incubator/setup-miniconda@v2
@@ -52,7 +52,7 @@ jobs:
name: pyscript-docs-review-${{ github.event.number }}
path: docs/_build/html/
# Deploy to S3
# Deploy to S3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1.6.1
with:

View File

@@ -19,8 +19,8 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
with:
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
- name: Setup
uses: conda-incubator/setup-miniconda@v2
@@ -42,13 +42,13 @@ jobs:
name: pyscript-docs-latest
path: docs/_build/html/
# Deploy to S3
# 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 }}
# Sync will only copy changed files
# Sync will only copy changed files
- name: Sync to S3
run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/unstable/

View File

@@ -3,7 +3,7 @@ name: '[CI] Prepare Release'
on:
push:
tags:
- '[0-9][0-9][0-9][0-9].[0-9][0-9].[0-9]+' # YYYY.MM.MICRO
- '[0-9][0-9][0-9][0-9].[0-9][0-9].[0-9]+' # YYYY.MM.MICRO
env:
MINICONDA_PYTHON_VERSION: py38
@@ -30,7 +30,7 @@ jobs:
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
# 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: |

View File

@@ -32,7 +32,7 @@ jobs:
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
# 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: |
@@ -49,7 +49,7 @@ jobs:
- name: Build and Test
run: make test
# Upload to S3
# Upload to S3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1.6.1
with:

View File

@@ -15,7 +15,7 @@ jobs:
working-directory: examples
steps:
# Deploy to S3
# Deploy to S3
- name: Checkout
uses: actions/checkout@v3
- name: Configure AWS credentials
@@ -24,5 +24,5 @@ jobs:
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
# 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

View File

@@ -4,17 +4,17 @@ Thank you for wanting to contribute to the PyScript project!
## Table of contents
- [Code of Conduct](#code-of-conduct)
- [Contributing](#contributing)
- [Reporting bugs](#reporting-bugs)
- [Reporting security issues](#reporting-security-issues)
- [Asking questions](#asking-questions)
- [Setting up your local environment and developing](#setting-up-your-local-environment-and-developing)
- [Places to start](#places-to-start)
- [Setting up your local environment and developing](#setting-up-your-local-environment-and-developing)
- [License terms for contributions](#license-terms-for-contributions)
- [Becoming a maintainer](#becoming-a-maintainer)
- [Trademarks](#trademarks)
- [Code of Conduct](#code-of-conduct)
- [Contributing](#contributing)
- [Reporting bugs](#reporting-bugs)
- [Reporting security issues](#reporting-security-issues)
- [Asking questions](#asking-questions)
- [Setting up your local environment and developing](#setting-up-your-local-environment-and-developing)
- [Places to start](#places-to-start)
- [Setting up your local environment and developing](#setting-up-your-local-environment-and-developing)
- [License terms for contributions](#license-terms-for-contributions)
- [Becoming a maintainer](#becoming-a-maintainer)
- [Trademarks](#trademarks)
# Code of Conduct
@@ -28,10 +28,10 @@ Bugs are tracked on the [project issues page](https://github.com/pyscript/pyscri
## Creating useful issues
- Use a clear and descriptive title.
- Describe the specific steps that reproduce the problem with as many details as possible so that someone can verify the issue.
- Describe the behavior you observed, and the behavior you had expected.
- Include screenshots if they help make the issue clear.
- Use a clear and descriptive title.
- Describe the specific steps that reproduce the problem with as many details as possible so that someone can verify the issue.
- Describe the behavior you observed, and the behavior you had expected.
- Include screenshots if they help make the issue clear.
## Reporting security issues
@@ -45,10 +45,10 @@ If you have questions about the project, using PyScript, or anything else, pleas
If you would like to contribute to PyScript, but you aren't sure where to begin, here are some suggestions.
- **Read over the existing documentation.** Are there things missing, or could they be clearer? Make some changes/additions to those documents.
- **Review the open issues.** Are they clear? Can you reproduce them? You can add comments, clarifications, or additions to those issues. If you think you have an idea of how to address the issue, submit a fix!
- **Look over the open pull requests.** Do you have comments or suggestions for the proposed changes? Add them.
- **Check out the examples.** Is there a use case that would be good to have sample code for? Create an example for it.
- **Read over the existing documentation.** Are there things missing, or could they be clearer? Make some changes/additions to those documents.
- **Review the open issues.** Are they clear? Can you reproduce them? You can add comments, clarifications, or additions to those issues. If you think you have an idea of how to address the issue, submit a fix!
- **Look over the open pull requests.** Do you have comments or suggestions for the proposed changes? Add them.
- **Check out the examples.** Is there a use case that would be good to have sample code for? Create an example for it.
## Setting up your local environment and developing

View File

@@ -20,15 +20,15 @@ To try PyScript, import the appropriate pyscript files into the `<head>` tag of
```html
<head>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head>
```
You can then use PyScript components in your html page. PyScript currently implements the following elements:
- `<py-script>`: can be used to define python code that is executable within the web page. The element itself is not rendered to the page and is only used to add logic
- `<py-repl>`: creates a REPL component that is rendered to the page as a code editor and allows users to write executable code
- `<py-script>`: can be used to define python code that is executable within the web page. The element itself is not rendered to the page and is only used to add logic
- `<py-repl>`: creates a REPL component that is rendered to the page as a code editor and allows users to write executable code
Check out the [the examples directory](examples) folder for more examples on how to use it, all you need to do is open them in Chrome.
@@ -40,16 +40,16 @@ Check out the [developing process](https://docs.pyscript.net/latest/development/
## Resources
- [Official docs](https://docs.pyscript.net)
- [Discussion board](https://community.anaconda.cloud/c/tech-topics/pyscript)
- [Home Page](https://pyscript.net/)
- [Blog Post](https://engineering.anaconda.com/2022/04/welcome-pyscript.html)
- [Discord Channel](https://discord.gg/BYB2kvyFwm)
- [Official docs](https://docs.pyscript.net)
- [Discussion board](https://community.anaconda.cloud/c/tech-topics/pyscript)
- [Home Page](https://pyscript.net/)
- [Blog Post](https://engineering.anaconda.com/2022/04/welcome-pyscript.html)
- [Discord Channel](https://discord.gg/BYB2kvyFwm)
## Notes
- This is an extremely experimental project, so expect things to break!
- PyScript has been only tested on Chrome at the moment.
- This is an extremely experimental project, so expect things to break!
- PyScript has been only tested on Chrome at the moment.
## Governance

View File

@@ -4,7 +4,7 @@ This page is meant for troubleshooting common problems with PyScript.
## Table of contents:
- [Make Setup](#make-setup)
- [Make Setup](#make-setup)
## Make setup

View File

@@ -1,78 +1,81 @@
<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" />
<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">Altair</a>
</div>
</nav>
<section class="pyscript">
<div id="altair"></div>
<py-tutor>
<py-config>
packages = [
"altair",
"pandas",
"vega_datasets"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-script>
import altair as alt
from vega_datasets import data
<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" />
<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">Altair</a>
</div>
</nav>
<section class="pyscript">
<div id="altair"></div>
<py-tutor>
<py-config>
packages = [
"altair",
"pandas",
"vega_datasets"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-script>
import altair as alt
from vega_datasets import data
source = data.movies.url
source = data.movies.url
pts = alt.selection(type="single", encodings=['x'])
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')
)
)
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
)
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)
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>
display(alt.vconcat(
rect + circ,
bar
).resolve_legend(
color="independent",
size="independent"
), target="altair")
</py-script>
</py-tutor>
</section>
</body>
</html>

View File

@@ -1,36 +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 = [
"../build/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>
<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 = [
"../build/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>

View File

@@ -1,91 +1,91 @@
body {
margin: 0;
margin: 0;
}
.pyscript {
margin: 0.5rem;
margin: 0.5rem;
}
.code {
display: flex;
position: absolute;
right: 0px;
z-index: 9998;
top: 7rem;
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: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;
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;
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;
margin: 0;
font-style: italic;
font-size: small;
}
.language-html,
.language-python {
float: left;
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;
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;
position: sticky;
width: 100%;
top: 0;
left: 0;
z-index: 9999;
}
.logo {
padding-right: 10px;
font-size: 28px;
height: 30px;
max-width: inherit;
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;
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;
display: flex;
align-items: center;
padding: 0.5rem 1rem;
}

View File

@@ -1,74 +1,74 @@
.example {
margin-bottom: 5rem;
margin-bottom: 5rem;
}
.example h2 {
/* color: #000000; */
font-family: "Inconsolata", monospace;
font-size: 2.25rem;
margin-bottom: 1rem;
/* 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;
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;
background-color: var(--color-primary);
color: #1d1d22;
}
.card a h2 {
color: var(--color-primary);
margin: 0;
font-family: "Inconsolata", monospace;
font-size: 2.25rem;
color: var(--color-primary);
margin: 0;
font-family: "Inconsolata", monospace;
font-size: 2.25rem;
}
.card a p {
color: var(--text-color);
color: var(--text-color);
}
a .card {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.card-content {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.card-content a,
.card-content a:visited {
color: var(--color-primary);
color: var(--color-primary);
}
.container-card {
max-width: 1500px;
margin: 0 auto;
display: grid;
gap: 1rem;
max-width: 1500px;
margin: 0 auto;
display: grid;
gap: 1rem;
}
@media (min-width: 600px) {
.container-card {
grid-template-columns: repeat(2, 1fr);
}
.container-card {
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 900px) {
.container-card {
grid-template-columns: repeat(4, 1fr);
}
.container-card {
grid-template-columns: repeat(4, 1fr);
}
}

View File

@@ -3,23 +3,23 @@
@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);
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;
max-width: 1510px;
margin: auto;
padding: 0 2rem;
}
.title-main {
font-size: 4.25rem;
font-family: "Inconsolata", monospace;
text-align: center;
margin: 2rem 0;
font-size: 4.25rem;
font-family: "Inconsolata", monospace;
text-align: center;
margin: 2rem 0;
}

View File

@@ -1,22 +1,22 @@
*,
*:after,
*:before {
margin: 0;
padding: 0;
box-sizing: border-box;
text-decoration: none;
margin: 0;
padding: 0;
box-sizing: border-box;
text-decoration: none;
}
body {
font-size: 100%;
list-style-type: none;
font-size: 100%;
list-style-type: none;
}
p {
font-family: "Inconsolata", monospace;
font-weight: 400;
font-family: "Inconsolata", monospace;
font-weight: 400;
}
a {
text-decoration: none;
text-decoration: none;
}

View File

@@ -1,6 +1,6 @@
:root {
--color-primary: #fda703;
--color-secondary: #1d1d22;
--text-color: white;
--card-shadow: 0px 5px 11px 0px rgb(0 0 0 / 15%);
--color-primary: #fda703;
--color-secondary: #1d1d22;
--text-color: white;
--card-shadow: 0px 5px 11px 0px rgb(0 0 0 / 15%);
}

View File

@@ -1,26 +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>
<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>

View File

@@ -1,42 +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
<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)
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
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)
async def asyncCallLoop2():
for i in range(3):
js.console.log('B', i)
await asyncio.sleep(2)
asyncCallLoop2()
</py-script>
</div>
</body>
asyncCallLoop2()
</py-script>
</div>
</body>
</html>

View File

@@ -1,39 +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
<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)
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
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>
for i in range(3):
js.console.log('B', i)
await asyncio.sleep(2)
</py-script>
</div>
</body>
</html>

View File

@@ -1,42 +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
<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)
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
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)
async def asyncCall2():
await asyncio.sleep(2)
for i in range(3):
js.console.log('B', i)
asyncCall2()
</py-script>
</div>
</body>
for i in range(3):
js.console.log('B', i)
asyncCall2()
</py-script>
</div>
</body>
</html>

View File

@@ -1,36 +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
<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('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>
for i in range(3):
js.console.log('B', i)
await asyncio.sleep(2)
</py-script>
</div>
</body>
</html>

View File

@@ -1,19 +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>
<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>

View File

@@ -1,81 +1,86 @@
<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>
<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" />
<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>
<link rel="stylesheet" href="./assets/css/examples.css" />
</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>
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
</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 = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-config>
packages = [
"pandas",
"bokeh",
"xyzservices"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-script id="main">
import json
import pyodide
<py-script id="main">
import json
import pyodide
from js import Bokeh, console, JSON
from js import Bokeh, console, JSON
from bokeh.embed import json_item
from bokeh.plotting import figure
from bokeh.resources import CDN
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)
# 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"))
# 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>
Bokeh.embed.embed_item(JSON.parse(p_json))
</py-script>
</section>
</py-tutor>
</body>
</html>

View File

@@ -1,131 +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" />
<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 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>
<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 = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-config>
packages = [
"https://cdn.holoviz.org/panel/0.14.3/dist/wheels/bokeh-2.4.3-py3-none-any.whl",
"numpy",
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-script id="main">
import asyncio
import json
import pyodide
<py-script id="main">
import asyncio
import json
import pyodide
from js import Bokeh, console, JSON
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
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}')
# 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}'
def callback(attr, old, new):
div.text = f'Amplitude is: {new}'
p.on_change('value', callback)
p.on_change('value', callback)
row = Row(children=[p, div])
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
)
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]
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__,
))
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))
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))
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')
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)
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)
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>
asyncio.ensure_future(show(row, 'myplot'))
</py-script>
</section>
</py-tutor>
</body>
</html>

View File

@@ -1,134 +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" />
<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;
}
<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>
@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 = [
"../build/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>
<section class="pyscript">
<py-tutor modules="d3.py">
<py-config>
plugins = [
"../build/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 },
];
<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 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 arc = d3
.arc()
.innerRadius(210)
.outerRadius(310)
.padRadius(300)
.padAngle(2 / 300)
.cornerRadius(8);
const js = d3.select("#js");
js.select(".loading").remove();
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");
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));
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");
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", "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>
text.append("tspan")
.style("font-size", "18")
.attr("x", "0")
.attr("dy", "1.3em")
.text(d.value);
}
</script>
</body>
</html>

View File

@@ -1,69 +1,72 @@
<html>
<head>
<title>Folium</title>
<meta charset="utf-8" />
<link rel="icon" type="image/x-icon" href="./favicon.png" />
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
</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>
<head>
<title>Folium</title>
<meta charset="utf-8" />
<link rel="icon" type="image/x-icon" href="./favicon.png" />
<link
rel="stylesheet"
href="https://pyscript.net/latest/pyscript.css"
/>
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
</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 = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-tutor>
<py-config>
packages = [
"folium",
"pandas"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-script>
import folium
import json
import pandas as pd
<py-script>
import folium
import json
import pandas as pd
from pyodide.http import open_url
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())
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)
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.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)
folium.LayerControl().add_to(m)
display(m, target="folium")
</py-script>
</py-tutor>
</section>
</body>
display(m, target="folium")
</py-script>
</py-tutor>
</section>
</body>
</html>

View File

@@ -1,43 +1,46 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>PyScript Hello World</title>
<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" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head>
<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" />
<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">Hello World</a>
</div>
</nav>
<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 = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-tutor>
<py-config>
plugins = [
"../build/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 datetime import datetime
now = datetime.now()
display(now.strftime("%m/%d/%Y, %H:%M:%S"))
</py-script>
</section>
</py-tutor>
</body>
<section class="pyscript">
Hello world! <br />
This is the current date and time, as computed by Python:
<py-script>
from datetime import datetime
now = datetime.now()
display(now.strftime("%m/%d/%Y, %H:%M:%S"))
</py-script>
</section>
</py-tutor>
</body>
</html>

View File

@@ -1,277 +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>
<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>&lt;py-script&gt;</code> tag</p>
</div>
</div>
<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>&lt;py-script&gt;</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>&lt;py-script&gt;</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>&lt;py-script&gt;</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="./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="./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.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>&lt;py-list&gt;</code></p>
</div>
</div>
</div>
</section>
<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>&lt;py-list&gt;</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>
<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="./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>
<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>
<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>&lt;py-script&gt;</code> tag
</p>
</div>
</div>
</div>
</section>
<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>&lt;py-script&gt;</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>
<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="./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_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_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.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="./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>
<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>

View File

@@ -2,34 +2,34 @@ html,
body,
ul,
li {
margin: 0;
border: 0;
padding: 0;
margin: 0;
border: 0;
padding: 0;
}
canvas {
display: block;
width: 762;
margin: 0 auto;
background-color: blue;
display: block;
width: 762;
margin: 0 auto;
background-color: blue;
}
p {
text-align: center;
text-align: center;
}
body {
overflow: hidden;
height: 100%;
overflow: hidden;
height: 100%;
}
html {
overflow: hidden;
height: 100%;
overflow: hidden;
height: 100%;
}
.info {
position: absolute;
top: 0;
left: 0;
position: absolute;
top: 0;
left: 0;
}

View File

@@ -1,43 +1,43 @@
(function () {
if (typeof Mario === "undefined") window.Mario = {};
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],
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);
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;
};
//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;
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];
}
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);
};
this.acc = 0.75;
this.vel += this.acc;
this.pos[1] += this.vel;
this.sprite.update(dt);
};
Bcoin.prototype.checkCollisions = function () {};
Bcoin.prototype.checkCollisions = function () {};
})();

View File

@@ -1,81 +1,84 @@
(function () {
if (typeof Mario === "undefined") window.Mario = {};
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.
//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;
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],
Mario.Entity.call(this, {
pos: options.pos,
sprite: options.sprite,
hitbox: [0, 0, 16, 16],
});
this.standing = true;
});
this.standing = true;
});
Mario.Util.inherits(Block, Mario.Floor);
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) {
Block.prototype.break = function () {
sounds.breakBlock.play();
new Mario.Rubble().spawn(this.pos);
var x = this.pos[0] / 16,
y = this.pos[1] / 16;
level.statics[y][x] = new Mario.Floor(this.pos, this.usedSprite);
y = this.pos[1] / 16;
delete level.blocks[y][x];
}
}
};
this.pos[1] += this.vel[1];
this.sprite.update(dt, gameTime);
};
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);
};
})();

View File

@@ -1,59 +1,62 @@
(function () {
if (typeof Mario === "undefined") window.Mario = {};
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],
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;
});
this.idx = level.items.length;
});
Mario.Util.inherits(Coin, Mario.Entity);
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],
];
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();
}
}
};
//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);
};
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();
};
//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];
};
Coin.prototype.collect = function () {
sounds.coin.currentTime = 0.05;
sounds.coin.play();
player.coins += 1;
delete level.items[this.idx];
};
})();

View File

@@ -1,34 +1,34 @@
(function () {
if (typeof Mario === "undefined") window.Mario = {};
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;
});
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.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.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 () {};
Entity.prototype.bump = function () {};
})();

View File

@@ -1,142 +1,145 @@
(function () {
if (typeof Mario === "undefined") window.Mario = {};
if (typeof Mario === "undefined") window.Mario = {};
var Fireball = (Mario.Fireball = function (pos) {
this.hit = 0;
this.standing = false;
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.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);
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);
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;
}
if (level.blocks[baseY + i][baseX + j]) {
level.blocks[baseY + i][baseX + j].isCollideWith(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;
}
}
}
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);
}
});
};
//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;
}
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]];
this.acc[1] = 0.5;
//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();
}
}
};
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.bump = function () {};
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 () {};
})();

View File

@@ -1,87 +1,90 @@
(function () {
if (typeof Mario === "undefined") window.Mario = {};
if (typeof Mario === "undefined") window.Mario = {};
var Fireflower = (Mario.Fireflower = function (pos) {
this.spawning = false;
this.waiting = 0;
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.Entity.call(this, {
pos: pos,
sprite: level.fireFlowerSprite,
hitbox: [0, 0, 16, 16],
});
});
});
Mario.Util.inherits(Fireflower, Mario.Entity);
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.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.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;
}
}
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);
};
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.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],
];
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);
}
}
};
//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 () {};
//This should never be called, but just in case.
Fireflower.prototype.bump = function () {};
})();

View File

@@ -1,45 +1,51 @@
(function () {
if (typeof Mario === "undefined") window.Mario = {};
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 = 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.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.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.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.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);
};
Flag.prototype.render = function () {
level.flagpoleSprites[2].render(
ctx,
this.pos[0] - 8,
this.pos[1],
vX,
vY,
);
};
})();

View File

@@ -1,75 +1,83 @@
(function () {
if (typeof Mario === "undefined") window.Mario = {};
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],
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);
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]),
];
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;
//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);
}
}
}
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 () {};
Floor.prototype.bonk = function () {};
})();

View File

@@ -1,14 +1,14 @@
var requestAnimFrame = (function () {
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
}
);
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
}
);
})();
//create the canvas
@@ -30,18 +30,18 @@ document.body.appendChild(canvas);
//viewport
var vX = 0,
vY = 0,
vWidth = 256,
vHeight = 240;
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",
"sprites/player.png",
"sprites/enemy.png",
"sprites/tiles.png",
"sprites/playerl.png",
"sprites/items.png",
"sprites/enemyr.png",
]);
resources.onReady(init);
@@ -52,194 +52,202 @@ 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();
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;
var now = Date.now();
var dt = (now - lastTime) / 1000.0;
update(dt);
render();
update(dt);
render();
lastTime = now;
requestAnimFrame(main);
lastTime = now;
requestAnimFrame(main);
}
function update(dt) {
gameTime += dt;
gameTime += dt;
handleInput(dt);
updateEntities(dt, gameTime);
handleInput(dt);
updateEntities(dt, gameTime);
checkCollisions();
checkCollisions();
}
function handleInput(dt) {
if (player.piping || player.dying || player.noInput) return; //don't accept input
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("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("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();
}
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);
});
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;
}
//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);
});
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);
});
level.enemies.forEach(function (ent) {
ent.update(dt, vX);
});
fireballs.forEach(function (fireball) {
fireball.update(dt);
});
level.pipes.forEach(function (pipe) {
pipe.update(dt);
});
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();
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();
});
//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);
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]);
}
//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);
});
//then items
level.items.forEach(function (item) {
renderEntity(item);
});
level.enemies.forEach(function (enemy) {
renderEntity(enemy);
});
level.enemies.forEach(function (enemy) {
renderEntity(enemy);
});
fireballs.forEach(function (fireball) {
renderEntity(fireball);
});
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 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);
}
//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);
});
//Mario goes INTO pipes, so naturally they go after.
level.pipes.forEach(function (pipe) {
renderEntity(pipe);
});
}
function renderEntity(entity) {
entity.render(ctx, vX, vY);
entity.render(ctx, vX, vY);
}

View File

@@ -1,144 +1,147 @@
(function () {
if (typeof Mario === "undefined") window.Mario = {};
if (typeof Mario === "undefined") window.Mario = {};
//TODO: On console the hitbox is smaller. Measure it and edit this.
//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],
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;
});
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.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);
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 (level.blocks[baseY + i][baseX + j]) {
level.blocks[baseY + i][baseX + j].isCollideWith(this);
if (this.dying) {
this.dying -= 1;
if (!this.dying) {
delete level.enemies[this.idx];
}
}
}
}
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);
};
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.isCollideWith = function (ent) {
if (ent instanceof Mario.Player && (this.dying || ent.invincibility)) {
return;
}
Goomba.prototype.collideWall = function () {
this.vel[0] = -this.vel[0];
};
//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.checkCollisions = function () {
if (this.flipping) {
return;
}
}
}
};
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;
};
var h = this.pos[1] % 16 === 0 ? 1 : 2;
var w = this.pos[0] % 16 === 0 ? 1 : 2;
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;
};
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;
};
})();

View File

@@ -1,61 +1,61 @@
(function () {
var pressedKeys = {};
var pressedKeys = {};
function setKey(event, status) {
var code = event.keyCode;
var key;
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);
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;
}
pressedKeys[key] = status;
}
document.addEventListener("keydown", function (e) {
setKey(e, true);
});
document.addEventListener("keydown", function (e) {
setKey(e, true);
});
document.addEventListener("keyup", function (e) {
setKey(e, false);
});
document.addEventListener("keyup", function (e) {
setKey(e, false);
});
window.addEventListener("blur", function () {
pressedKeys = {};
});
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;
},
};
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;
},
};
})();

View File

@@ -1,225 +1,228 @@
(function () {
if (typeof Mario === "undefined") window.Mario = {};
if (typeof Mario === "undefined") window.Mario = {};
var Koopa = (Mario.Koopa = function (pos, sprite, para) {
this.dying = false;
this.shell = false;
var Koopa = (Mario.Koopa = function (pos, sprite, para) {
this.dying = false;
this.shell = false;
this.para = para; //para. As in, is it a paratroopa?
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],
//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;
});
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.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;
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.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;
if (this.vel[0] != 0) {
this.left = this.vel[0] < 0;
}
} 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();
}
if (this.left) {
this.sprite.img = "sprites/enemy.png";
} else {
if (this.shell && ent instanceof Mario.Goomba) {
ent.bump();
} else this.collideWall();
this.sprite.img = "sprites/enemyr.png";
}
}
}
};
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;
}
};
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];
}
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;
};
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;
};
})();

View File

@@ -1,310 +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,
),
//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;
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 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]);
});
//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]);
});
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]);
});
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);
});
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);
});
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);
});
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);
});
twoBushes = [41, 89, 137];
twoBushes.forEach(function (bush) {
level.putTwoBush(bush, 12);
});
threeBushes = [11, 59, 106];
threeBushes.forEach(function (bush) {
level.putThreeBush(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);
//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);
//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();
music.underground.pause();
// music.overworld.currentTime = 0;
music.overworld.play();
});

View File

@@ -1,113 +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),
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),
],
});
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);
});
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]);
});
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.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);
level.putPipe(15, 13, 13);
music.overworld.pause();
music.underground.currentTime = 0;
music.underground.play();
music.overworld.pause();
music.underground.currentTime = 0;
music.underground.play();
});

View File

@@ -1,295 +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;
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;
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;
//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;
//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.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.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 = [];
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,
for (var i = 0; i < 15; i++) {
this.statics[i] = [];
this.scenery[i] = [];
this.blocks[i] = [];
}
});
};
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.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.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.putGoomba = function (x, y) {
this.enemies.push(
new Mario.Goomba([16 * x, 16 * y], this.goombaSprite()),
);
};
Level.prototype.putBush = function (x, y) {
this.scenery[y][x] = new Mario.Prop([x * 16, y * 16], this.bushSprite);
};
Level.prototype.putKoopa = function (x, y) {
this.enemies.push(
new Mario.Koopa([16 * x, 16 * y], this.koopaSprite(), false),
);
};
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.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.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.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,
);
}
}
};
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]);
};
//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.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.putCoin = function (x, y) {
this.items.push(new Mario.Coin([x * 16, y * 16], this.coinSprite()));
};
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.putCloud = function (x, y) {
this.scenery[y][x] = new Mario.Prop([x * 16, y * 16], this.cloudSprite);
};
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.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.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));
};
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));
};
})();

View File

@@ -1,129 +1,132 @@
(function () {
if (typeof Mario === "undefined") window.Mario = {};
if (typeof Mario === "undefined") window.Mario = {};
var Mushroom = (Mario.Mushroom = function (pos) {
this.spawning = false;
this.waiting = 0;
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.Entity.call(this, {
pos: pos,
sprite: level.superShroomSprite,
hitbox: [0, 0, 16, 16],
});
});
});
Mario.Util.inherits(Mushroom, Mario.Entity);
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.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);
Mushroom.prototype.spawn = function () {
if (player.power > 0) {
//replace this with a fire flower
var ff = new Mario.Fireflower(this.pos);
ff.spawn();
return;
}
if (level.blocks[baseY + i][baseX + j]) {
level.blocks[baseY + i][baseX + j].isCollideWith(this);
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;
}
}
}
this.isPlayerCollided();
};
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);
}
};
//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],
];
Mushroom.prototype.collideWall = function () {
this.vel[0] = -this.vel[0];
};
//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.checkCollisions = function () {
if (this.spawning) {
return;
}
var h = this.pos[1] % 16 == 0 ? 1 : 2;
var w = this.pos[0] % 16 == 0 ? 1 : 2;
Mushroom.prototype.bump = function () {
this.vel[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;
};
})();

View File

@@ -1,224 +1,228 @@
(function () {
if (typeof Mario === "undefined") window.Mario = {};
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;
//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;
//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;
}
if (this.direction === "UP" || this.direction === "DOWN") {
this.hitbox = [0, 0, 32, this.length * 16];
this.midsection = level.pipeUpMid;
this.endsection = level.pipeTop;
} else {
//entity is hitting it from the side, we're a wall
ent.collideWall(this);
this.hitbox = [0, 0, 16 * this.length, 32];
this.midsection = level.pipeSideMid;
this.endsection = level.pipeLeft;
}
}
}
};
};
//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();
};
Pipe.prototype.checkPipe = function () {
if (this.destination === undefined || !input.isDown(this.direction))
return;
//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
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;
}
};
//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,
);
//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);
}
}
}
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,
);
};
//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;
}
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;
}
};
};
})();

View File

@@ -1,498 +1,505 @@
(function () {
if (typeof Mario === "undefined") window.Mario = {};
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;
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;
} else this.jumping -= 1;
}
};
this.canJump = true;
this.invincibility = 0;
this.crouching = false;
this.fireballs = 0;
this.runheld = false;
this.noInput = false;
this.targetPos = [];
Player.prototype.setAnimation = function () {
if (this.dying) return;
Mario.Entity.call(this, {
pos: pos,
sprite: new Mario.Sprite(
"sprites/player.png",
[80, 32],
[16, 16],
0,
),
hitbox: [0, 0, 16, 16],
});
});
if (this.starTime) {
var index;
if (this.starTime > 60) index = Math.floor(this.starTime / 2) % 3;
else index = Math.floor(this.starTime / 8) % 3;
Mario.Util.inherits(Player, Mario.Entity);
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;
Player.prototype.run = function () {
this.maxSpeed = 2.5;
if (this.power == 2 && !this.runheld) {
this.shoot();
}
}
}
//okay cool, now set the sprite
if (this.crouching) {
this.sprite.pos[0] = 176;
this.sprite.speed = 0;
return;
}
this.runheld = true;
};
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;
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;
}
} else {
this.sprite.pos[0] = 80;
};
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;
}
if (this.shooting) {
this.sprite.pos[0] += 160;
this.shooting -= 1;
}
}
this.power = 0;
this.waiting = 0.5;
this.dying = 2;
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 (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];
}
if (level.statics[baseY + i][baseX + j]) {
level.statics[baseY + i][baseX + j].isCollideWith(this);
};
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;
}
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;
Player.prototype.flag = function () {
this.noInput = true;
this.flagging = true;
this.vel = [0, 2];
this.acc = [0, 0];
};
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;
};
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;
};
})();

View File

@@ -1,14 +1,14 @@
(function () {
if (typeof Mario === "undefined") window.Mario = {};
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;
});
//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);
};
//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);
};
})();

View File

@@ -1,61 +1,61 @@
//simple resource loader
(function () {
var resourceCache = {};
var loading = [];
var readyCallbacks = [];
var resourceCache = {};
var loading = [];
var readyCallbacks = [];
// Load an image url or an array of image urls
function load(urlOrArr) {
if (urlOrArr instanceof Array) {
urlOrArr.forEach(function (url) {
_load(url);
});
} else {
_load(urlOrArr);
}
}
function _load(url) {
if (resourceCache[url]) {
return resourceCache[url];
} else {
var img = new Image();
img.onload = function () {
resourceCache[url] = img;
if (isReady()) {
readyCallbacks.forEach(function (func) {
func();
});
// Load an image url or an array of image urls
function load(urlOrArr) {
if (urlOrArr instanceof Array) {
urlOrArr.forEach(function (url) {
_load(url);
});
} else {
_load(urlOrArr);
}
};
resourceCache[url] = false;
img.src = url;
}
}
function get(url) {
return resourceCache[url];
}
function _load(url) {
if (resourceCache[url]) {
return resourceCache[url];
} else {
var img = new Image();
img.onload = function () {
resourceCache[url] = img;
function isReady() {
var ready = true;
for (var k in resourceCache) {
if (resourceCache.hasOwnProperty(k) && !resourceCache[k]) {
ready = false;
}
if (isReady()) {
readyCallbacks.forEach(function (func) {
func();
});
}
};
resourceCache[url] = false;
img.src = url;
}
}
return ready;
}
function onReady(func) {
readyCallbacks.push(func);
}
function get(url) {
return resourceCache[url];
}
window.resources = {
load: load,
get: get,
onReady: onReady,
isReady: isReady,
};
function isReady() {
var ready = true;
for (var k in resourceCache) {
if (resourceCache.hasOwnProperty(k) && !resourceCache[k]) {
ready = false;
}
}
return ready;
}
function onReady(func) {
readyCallbacks.push(func);
}
window.resources = {
load: load,
get: get,
onReady: onReady,
isReady: isReady,
};
})();

View File

@@ -1,58 +1,64 @@
(function () {
if (typeof Mario === "undefined") window.Mario = {};
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 = [];
});
//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.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];
}
};
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 () {};
//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);
}
};
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,
);
}
};
})();

View File

@@ -1,56 +1,63 @@
(function () {
if (typeof Mario === "undefined") window.Mario = {};
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;
});
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.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.setFrame = function (frame) {
this._index = frame;
};
Sprite.prototype.render = function (ctx, posx, posy, vX, vY) {
var 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.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;
}
if (this.once && idx >= max) {
this.done = true;
return;
}
} else {
frame = 0;
}
var x = this.pos[0];
var y = this.pos[1];
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],
);
};
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],
);
};
})();

View File

@@ -1,127 +1,130 @@
(function () {
if (typeof Mario === "undefined") window.Mario = {};
if (typeof Mario === "undefined") window.Mario = {};
var Star = (Mario.Star = function (pos) {
this.spawning = false;
this.waiting = 0;
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.Entity.call(this, {
pos: pos,
sprite: level.starSprite,
hitbox: [0, 0, 16, 16],
});
});
});
Mario.Util.inherits(Star, Mario.Entity);
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.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.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);
Star.prototype.update = function (dt) {
if (this.spawning > 1) {
this.spawning -= 1;
if (this.spawning == 1) this.vel[1] = -0.5;
return;
}
if (level.blocks[baseY + i][baseX + j]) {
level.blocks[baseY + i][baseX + j].isCollideWith(this);
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;
}
}
}
this.isPlayerCollided();
};
if (this.standing) {
this.standing = false;
this.vel[1] = -3;
}
//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 (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);
}
};
//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.collideWall = function () {
this.vel[0] = -this.vel[0];
};
Star.prototype.bump = function () {
this.vel[1] = -2;
};
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;
};
})();

View File

@@ -1,14 +1,14 @@
(function () {
if (typeof Mario === "undefined") {
window.Mario = {};
}
if (typeof Mario === "undefined") {
window.Mario = {};
}
var Util = (Mario.Util = {});
var Util = (Mario.Util = {});
Util.inherits = function (subclass, superclass) {
function Surrogate() {}
Util.inherits = function (subclass, superclass) {
function Surrogate() {}
Surrogate.prototype = superclass.prototype;
subclass.prototype = new Surrogate();
};
Surrogate.prototype = superclass.prototype;
subclass.prototype = new Surrogate();
};
})();

View File

@@ -1,30 +1,30 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<head>
<meta charset="utf-8" />
<title>PyMarkdown</title>
<title>PyMarkdown</title>
<link rel="icon" type="image/png" href="favicon.png" />
<link rel="stylesheet" href="../build/pyscript.css" />
<link rel="icon" type="image/png" href="favicon.png" />
<link rel="stylesheet" href="../build/pyscript.css" />
<link rel="stylesheet" href="./assets/css/examples.css" />
<script defer src="../build/pyscript.js"></script>
</head>
<link rel="stylesheet" href="./assets/css/examples.css" />
<script defer src="../build/pyscript.js"></script>
</head>
<body>
<py-tutor>
<py-config>
packages = [
"markdown"
]
plugins = [
"../build/plugins/python/py_markdown.py",
"../build/plugins/python/py_tutor.py"
]
</py-config>
<body>
<py-tutor>
<py-config>
packages = [
"markdown"
]
plugins = [
"../build/plugins/python/py_markdown.py",
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-md>#Hello world!</py-md>
</py-tutor>
</body>
<py-md>#Hello world!</py-md>
</py-tutor>
</body>
</html>

View File

@@ -1,70 +1,73 @@
<html>
<head>
<title>Matplotlib</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" />
</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">Matplotlib</a>
</div>
</nav>
<section class="pyscript">
<div id="mpl"></div>
<head>
<title>Matplotlib</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" />
</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">Matplotlib</a>
</div>
</nav>
<section class="pyscript">
<div id="mpl"></div>
<py-tutor>
<py-config>
packages = [
"matplotlib"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-tutor>
<py-config>
packages = [
"matplotlib"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-script>
import matplotlib.pyplot as plt
import matplotlib.tri as tri
import numpy as np
<py-script>
import matplotlib.pyplot as plt
import matplotlib.tri as tri
import numpy as np
# First create the x and y coordinates of the points.
n_angles = 36
n_radii = 8
min_radius = 0.25
radii = np.linspace(min_radius, 0.95, n_radii)
# First create the x and y coordinates of the points.
n_angles = 36
n_radii = 8
min_radius = 0.25
radii = np.linspace(min_radius, 0.95, n_radii)
angles = np.linspace(0, 2 * np.pi, n_angles, endpoint=False)
angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)
angles[:, 1::2] += np.pi / n_angles
angles = np.linspace(0, 2 * np.pi, n_angles, endpoint=False)
angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)
angles[:, 1::2] += np.pi / n_angles
x = (radii * np.cos(angles)).flatten()
y = (radii * np.sin(angles)).flatten()
z = (np.cos(radii) * np.cos(3 * angles)).flatten()
x = (radii * np.cos(angles)).flatten()
y = (radii * np.sin(angles)).flatten()
z = (np.cos(radii) * np.cos(3 * angles)).flatten()
# Create the Triangulation; no triangles so Delaunay triangulation created.
triang = tri.Triangulation(x, y)
# Create the Triangulation; no triangles so Delaunay triangulation created.
triang = tri.Triangulation(x, y)
# Mask off unwanted triangles.
triang.set_mask(np.hypot(x[triang.triangles].mean(axis=1),
y[triang.triangles].mean(axis=1))
< min_radius)
# Mask off unwanted triangles.
triang.set_mask(np.hypot(x[triang.triangles].mean(axis=1),
y[triang.triangles].mean(axis=1))
< min_radius)
fig1, ax1 = plt.subplots()
ax1.set_aspect('equal')
tpc = ax1.tripcolor(triang, z, shading='flat')
fig1.colorbar(tpc)
ax1.set_title('tripcolor of Delaunay triangulation, flat shading')
fig1, ax1 = plt.subplots()
ax1.set_aspect('equal')
tpc = ax1.tripcolor(triang, z, shading='flat')
fig1.colorbar(tpc)
ax1.set_title('tripcolor of Delaunay triangulation, flat shading')
display(fig1, target="mpl")
</py-script>
</py-tutor>
</section>
</body>
display(fig1, target="mpl")
</py-script>
</py-tutor>
</section>
</body>
</html>

View File

@@ -1,35 +1,38 @@
<html>
<head>
<link rel="icon" type="image/x-icon" href="./favicon.png" />
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<head>
<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" />
</head>
<link rel="stylesheet" href="./assets/css/examples.css" />
</head>
<body>
<py-tutor>
<py-config>
packages = [
"numpy",
"networkx",
"matplotlib"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<body>
<py-tutor>
<py-config>
packages = [
"numpy",
"networkx",
"matplotlib"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-script>
import numpy as np
import networkx as nx
</py-script>
<py-script>
import numpy as np
import networkx as nx
</py-script>
<p>Message passing with linear algebra: a demo.</p>
<p>Imagine we have a chain graph that looks like this:</p>
<pre><code>O --> 1 --> 2 --> 3</code></pre>
<p>In NetworkX this graph would look like the following:</p>
<pre>
<p>Message passing with linear algebra: a demo.</p>
<p>Imagine we have a chain graph that looks like this:</p>
<pre><code>O --> 1 --> 2 --> 3</code></pre>
<p>In NetworkX this graph would look like the following:</p>
<pre>
<py-script>
G = nx.Graph()
nodes = list(range(4))
@@ -37,29 +40,30 @@ G.add_edges_from(zip(nodes[0:-1], nodes[1:]))
print(G.edges())
</py-script>
</pre>
<p>This chain graph has the following adjacency matrix:</p>
<pre>
<p>This chain graph has the following adjacency matrix:</p>
<pre>
<py-script>
adj_mat = np.eye(4, k=1)
print(f"A: {adj_mat}")
</py-script>
</pre>
<p>And imagine that we have a message that lives on the graph:</p>
<pre>
<p>And imagine that we have a message that lives on the graph:</p>
<pre>
<py-script>
message = np.array([1.0, 0.0, 0.0, 0.0])
print(f"message: {message}")
</py-script>
</pre>
<p>
Try out message passing below by doing any one of the following steps:
</p>
<pre><code>message @ adj_mat</code></pre>
<pre><code>message @ adj_mat @ adj_mat</code></pre>
<pre><code>message @ adj_mat @ adj_mat @ adj_mat</code></pre>
<div>
<py-repl id="my-repl" auto-generate="true"> </py-repl>
</div>
</py-tutor>
</body>
<p>
Try out message passing below by doing any one of the following
steps:
</p>
<pre><code>message @ adj_mat</code></pre>
<pre><code>message @ adj_mat @ adj_mat</code></pre>
<pre><code>message @ adj_mat @ adj_mat @ adj_mat</code></pre>
<div>
<py-repl id="my-repl" auto-generate="true"> </py-repl>
</div>
</py-tutor>
</body>
</html>

View File

@@ -1,186 +1,196 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/x-icon" href="./favicon.png" />
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/x-icon" href="./favicon.png" />
<title>micrograd</title>
<title>micrograd</title>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link
rel="stylesheet"
href="https://pyscript.net/latest/pyscript.css"
/>
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
rel="stylesheet"
crossorigin="anonymous"
/>
</head>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
rel="stylesheet"
crossorigin="anonymous"
/>
</head>
<body
style="
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
"
>
<h1>Micrograd - A tiny Autograd engine (with a bite! :))</h1>
<br />
<body
style="
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
"
>
<h1>Micrograd - A tiny Autograd engine (with a bite! :))</h1>
<br />
<py-config>
packages = [
"micrograd",
"numpy",
"matplotlib"
]
</py-config>
<py-config>
packages = [
"micrograd",
"numpy",
"matplotlib"
]
</py-config>
<div>
<p>
<a href="https://github.com/karpathy/micrograd">Micrograd</a> is a tiny
Autograd engine created by
<a href="https://twitter.com/karpathy">Andrej Karpathy</a>. This app
recreates the
<a href="https://github.com/karpathy/micrograd/blob/master/demo.ipynb"
>demo</a
>
he prepared for this package using pyscript to train a basic model,
written in Python, natively in the browser. <br />
</p>
</div>
<div>
<p>
You may run each Python REPL cell interactively by pressing (Shift +
Enter) or (Ctrl + Enter). You can also modify the code directly as you
wish. If you want to run all the code at once, not each cell
individually, you may instead click the 'Run All' button. Training the
model takes between 1-2 min if you decide to 'Run All' at once. 'Run
All' is your only option if you are running this on a mobile device
where you cannot press (Shift + Enter). After the model is trained, a
plot image should be displayed depicting the model's ability to classify
the data. <br />
</p>
<p>
Currently the <code>&gt;</code> symbol is being imported incorrectly as
<code>&amp;gt;</code> into the REPL's. In this app the
<code>&gt;</code> symbol has been replaced with
<code>().__gt__()</code> so you can run the code without issue. Ex:
instead of <code>a &gt; b</code>, you will see
<code>(a).__gt__(b)</code> instead. <br />
</p>
<py-script>
import js; js.document.getElementById('python-status').innerHTML = 'Python is now ready. You may proceed.'
</py-script>
<div id="python-status">Python is currently starting. Please wait...</div>
<button
id="run-all-button"
class="btn btn-primary"
type="submit"
py-onClick="run_all_micrograd_demo()"
>
Run All</button
><br />
<py-script src="/micrograd_ai.py"></py-script>
<div id="micrograd-run-all-print-div"></div>
<br />
<div id="micrograd-run-all-fig1-div"></div>
<div id="micrograd-run-all-fig2-div"></div>
<br />
</div>
<py-repl auto-generate="false">
import random import numpy as np import matplotlib.pyplot as plt </py-repl
><br />
<py-repl auto-generate="false">
from micrograd.engine import Value from micrograd.nn import Neuron, Layer,
MLP </py-repl
><br />
<py-repl auto-generate="true">
np.random.seed(1337) random.seed(1337) </py-repl
><br />
<py-repl auto-generate="true">
#An adaptation of sklearn's make_moons function
https://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_moons.html
def make_moons(n_samples=100, noise=None): n_samples_out, n_samples_in =
n_samples, n_samples outer_circ_x = np.cos(np.linspace(0, np.pi,
n_samples_out)) outer_circ_y = np.sin(np.linspace(0, np.pi,
n_samples_out)) inner_circ_x = 1 - np.cos(np.linspace(0, np.pi,
n_samples_in)) inner_circ_y = 1 - np.sin(np.linspace(0, np.pi,
n_samples_in)) - 0.5 X = np.vstack([np.append(outer_circ_x, inner_circ_x),
np.append(outer_circ_y, inner_circ_y)]).T y =
np.hstack([np.zeros(n_samples_out, dtype=np.intp), np.ones(n_samples_in,
dtype=np.intp)]) if noise is not None: X += np.random.normal(loc=0.0,
scale=noise, size=X.shape) return X, y X, y = make_moons(n_samples=100,
noise=0.1) </py-repl
><br />
<py-repl auto-generate="true">
y = y*2 - 1 # make y be -1 or 1 # visualize in 2D
plt.figure(figsize=(5,5)) plt.scatter(X[:,0], X[:,1], c=y, s=20,
cmap='jet') plt </py-repl
><br />
<py-repl auto-generate="true">
model = MLP(2, [16, 16, 1]) # 2-layer neural network print(model)
print("number of parameters", len(model.parameters())) </py-repl
><br />
<div>
<p>
<a href="https://github.com/karpathy/micrograd">Micrograd</a> is
a tiny Autograd engine created by
<a href="https://twitter.com/karpathy">Andrej Karpathy</a>. This
app recreates the
<a
href="https://github.com/karpathy/micrograd/blob/master/demo.ipynb"
>demo</a
>
he prepared for this package using pyscript to train a basic
model, written in Python, natively in the browser. <br />
</p>
</div>
<div>
<p>
You may run each Python REPL cell interactively by pressing
(Shift + Enter) or (Ctrl + Enter). You can also modify the code
directly as you wish. If you want to run all the code at once,
not each cell individually, you may instead click the 'Run All'
button. Training the model takes between 1-2 min if you decide
to 'Run All' at once. 'Run All' is your only option if you are
running this on a mobile device where you cannot press (Shift +
Enter). After the model is trained, a plot image should be
displayed depicting the model's ability to classify the data.
<br />
</p>
<p>
Currently the <code>&gt;</code> symbol is being imported
incorrectly as <code>&amp;gt;</code> into the REPL's. In this
app the <code>&gt;</code> symbol has been replaced with
<code>().__gt__()</code> so you can run the code without issue.
Ex: instead of <code>a &gt; b</code>, you will see
<code>(a).__gt__(b)</code> instead. <br />
</p>
<py-script>
import js; js.document.getElementById('python-status').innerHTML = 'Python is now ready. You may proceed.'
</py-script>
<div id="python-status">
Python is currently starting. Please wait...
</div>
<button
id="run-all-button"
class="btn btn-primary"
type="submit"
py-onClick="run_all_micrograd_demo()"
>
Run All</button
><br />
<py-script src="/micrograd_ai.py"></py-script>
<div id="micrograd-run-all-print-div"></div>
<br />
<div id="micrograd-run-all-fig1-div"></div>
<div id="micrograd-run-all-fig2-div"></div>
<br />
</div>
<py-repl auto-generate="false">
import random import numpy as np import matplotlib.pyplot as plt </py-repl
><br />
<py-repl auto-generate="false">
from micrograd.engine import Value from micrograd.nn import Neuron,
Layer, MLP </py-repl
><br />
<py-repl auto-generate="true">
np.random.seed(1337) random.seed(1337) </py-repl
><br />
<py-repl auto-generate="true">
#An adaptation of sklearn's make_moons function
https://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_moons.html
def make_moons(n_samples=100, noise=None): n_samples_out,
n_samples_in = n_samples, n_samples outer_circ_x =
np.cos(np.linspace(0, np.pi, n_samples_out)) outer_circ_y =
np.sin(np.linspace(0, np.pi, n_samples_out)) inner_circ_x = 1 -
np.cos(np.linspace(0, np.pi, n_samples_in)) inner_circ_y = 1 -
np.sin(np.linspace(0, np.pi, n_samples_in)) - 0.5 X =
np.vstack([np.append(outer_circ_x, inner_circ_x),
np.append(outer_circ_y, inner_circ_y)]).T y =
np.hstack([np.zeros(n_samples_out, dtype=np.intp),
np.ones(n_samples_in, dtype=np.intp)]) if noise is not None: X +=
np.random.normal(loc=0.0, scale=noise, size=X.shape) return X, y X,
y = make_moons(n_samples=100, noise=0.1) </py-repl
><br />
<py-repl auto-generate="true">
y = y*2 - 1 # make y be -1 or 1 # visualize in 2D
plt.figure(figsize=(5,5)) plt.scatter(X[:,0], X[:,1], c=y, s=20,
cmap='jet') plt </py-repl
><br />
<py-repl auto-generate="true">
model = MLP(2, [16, 16, 1]) # 2-layer neural network print(model)
print("number of parameters", len(model.parameters())) </py-repl
><br />
<div>
Line 24 has been changed from: <br />
<code
>accuracy = [(yi &gt; 0) == (scorei.data &gt; 0) for yi, scorei in
zip(yb, scores)]</code
><br />
to: <br />
<code
>accuracy = [((yi).__gt__(0)) == ((scorei.data).__gt__(0)) for yi,
scorei in zip(yb, scores)]</code
><br />
</div>
<div>
Line 24 has been changed from: <br />
<code
>accuracy = [(yi &gt; 0) == (scorei.data &gt; 0) for yi, scorei
in zip(yb, scores)]</code
><br />
to: <br />
<code
>accuracy = [((yi).__gt__(0)) == ((scorei.data).__gt__(0)) for
yi, scorei in zip(yb, scores)]</code
><br />
</div>
<py-repl auto-generate="true">
# loss function def loss(batch_size=None): # inline DataLoader :) if
batch_size is None: Xb, yb = X, y else: ri =
np.random.permutation(X.shape[0])[:batch_size] Xb, yb = X[ri], y[ri]
inputs = [list(map(Value, xrow)) for xrow in Xb] # forward the model to
get scores scores = list(map(model, inputs)) # svm "max-margin" loss
losses = [(1 + -yi*scorei).relu() for yi, scorei in zip(yb, scores)]
data_loss = sum(losses) * (1.0 / len(losses)) # L2 regularization alpha =
1e-4 reg_loss = alpha * sum((p*p for p in model.parameters())) total_loss
= data_loss + reg_loss # also get accuracy accuracy = [((yi).__gt__(0)) ==
((scorei.data).__gt__(0)) for yi, scorei in zip(yb, scores)] return
total_loss, sum(accuracy) / len(accuracy) total_loss, acc = loss()
print(total_loss, acc) </py-repl
><br />
<py-repl auto-generate="true">
# optimization for k in range(20): #was 100. Accuracy can be further
improved w/ more epochs (to 100%). # forward total_loss, acc = loss() #
backward model.zero_grad() total_loss.backward() # update (sgd)
learning_rate = 1.0 - 0.9*k/100 for p in model.parameters(): p.data -=
learning_rate * p.grad if k % 1 == 0: print(f"step {k} loss
{total_loss.data}, accuracy {acc*100}%") </py-repl
><br />
<div>
<p>
Please wait for the training loop above to complete. It will not print
out stats until it has completely finished. This typically takes 1-2
min. <br /><br />
<py-repl auto-generate="true">
# loss function def loss(batch_size=None): # inline DataLoader :) if
batch_size is None: Xb, yb = X, y else: ri =
np.random.permutation(X.shape[0])[:batch_size] Xb, yb = X[ri], y[ri]
inputs = [list(map(Value, xrow)) for xrow in Xb] # forward the model
to get scores scores = list(map(model, inputs)) # svm "max-margin"
loss losses = [(1 + -yi*scorei).relu() for yi, scorei in zip(yb,
scores)] data_loss = sum(losses) * (1.0 / len(losses)) # L2
regularization alpha = 1e-4 reg_loss = alpha * sum((p*p for p in
model.parameters())) total_loss = data_loss + reg_loss # also get
accuracy accuracy = [((yi).__gt__(0)) == ((scorei.data).__gt__(0))
for yi, scorei in zip(yb, scores)] return total_loss, sum(accuracy)
/ len(accuracy) total_loss, acc = loss() print(total_loss, acc) </py-repl
><br />
<py-repl auto-generate="true">
# optimization for k in range(20): #was 100. Accuracy can be further
improved w/ more epochs (to 100%). # forward total_loss, acc =
loss() # backward model.zero_grad() total_loss.backward() # update
(sgd) learning_rate = 1.0 - 0.9*k/100 for p in model.parameters():
p.data -= learning_rate * p.grad if k % 1 == 0: print(f"step {k}
loss {total_loss.data}, accuracy {acc*100}%") </py-repl
><br />
<div>
<p>
Please wait for the training loop above to complete. It will not
print out stats until it has completely finished. This typically
takes 1-2 min. <br /><br />
Line 9 has been changed from: <br />
<code>Z = np.array([s.data &gt; 0 for s in scores])</code><br />
to: <br />
<code>Z = np.array([(s.data).__gt__(0) for s in scores])</code><br />
</p>
</div>
<py-repl auto-generate="true">
h = 0.25 x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 y_min, y_max
= X[:, 1].min() - 1, X[:, 1].max() + 1 xx, yy =
np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h)) Xmesh
= np.c_[xx.ravel(), yy.ravel()] inputs = [list(map(Value, xrow)) for xrow
in Xmesh] scores = list(map(model, inputs)) Z =
np.array([(s.data).__gt__(0) for s in scores]) Z = Z.reshape(xx.shape) fig
= plt.figure() plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral, alpha=0.8)
plt.scatter(X[:, 0], X[:, 1], c=y, s=40, cmap=plt.cm.Spectral)
plt.xlim(xx.min(), xx.max()) plt.ylim(yy.min(), yy.max()) plt </py-repl
><br />
<py-repl auto-generate="true"> 1+1 </py-repl><br />
</body>
Line 9 has been changed from: <br />
<code>Z = np.array([s.data &gt; 0 for s in scores])</code><br />
to: <br />
<code>Z = np.array([(s.data).__gt__(0) for s in scores])</code
><br />
</p>
</div>
<py-repl auto-generate="true">
h = 0.25 x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 y_min,
y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 xx, yy =
np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
Xmesh = np.c_[xx.ravel(), yy.ravel()] inputs = [list(map(Value,
xrow)) for xrow in Xmesh] scores = list(map(model, inputs)) Z =
np.array([(s.data).__gt__(0) for s in scores]) Z =
Z.reshape(xx.shape) fig = plt.figure() plt.contourf(xx, yy, Z,
cmap=plt.cm.Spectral, alpha=0.8) plt.scatter(X[:, 0], X[:, 1], c=y,
s=40, cmap=plt.cm.Spectral) plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max()) plt </py-repl
><br />
<py-repl auto-generate="true"> 1+1 </py-repl><br />
</body>
</html>
<!-- Adapted by Mat Miller -->

View File

@@ -1,385 +1,411 @@
<html>
<head>
<title>
Visualization of Mandelbrot, Julia and Newton sets with NumPy and HTML5
canvas
</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" />
<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;
}
<head>
<title>
Visualization of Mandelbrot, Julia and Newton sets with NumPy and
HTML5 canvas
</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" />
<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;
}
canvas {
display: none;
}
canvas {
display: none;
}
@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"
>Fractals with NumPy and canvas</a
>
</div>
</nav>
<section class="pyscript">
<div
style="display: flex; flex-direction: column; gap: 1em; width: 600px"
>
<div id="mandelbrot">
<div style="text-align: center">Mandelbrot set</div>
<div>
<div class="loading"></div>
<canvas></canvas>
</div>
</div>
<div id="julia">
<div style="text-align: center">Julia set</div>
<div>
<div class="loading"></div>
<canvas></canvas>
</div>
</div>
<div id="newton">
<div style="text-align: center">Newton set</div>
<fieldset style="display: flex; flex-direction: row; gap: 1em">
<div>
<span style="white-space: pre">p(z) = </span
><input id="poly" type="text" value="z**3 - 2*z + 2" />
@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"
>Fractals with NumPy and canvas</a
>
</div>
<div>
<span style="white-space: pre">a = </span
><input id="coef" type="text" value="1" style="width: 40px" />
</nav>
<section class="pyscript">
<div
style="
display: flex;
flex-direction: column;
gap: 1em;
width: 600px;
"
>
<div id="mandelbrot">
<div style="text-align: center">Mandelbrot set</div>
<div>
<div class="loading"></div>
<canvas></canvas>
</div>
</div>
<div id="julia">
<div style="text-align: center">Julia set</div>
<div>
<div class="loading"></div>
<canvas></canvas>
</div>
</div>
<div id="newton">
<div style="text-align: center">Newton set</div>
<fieldset
style="display: flex; flex-direction: row; gap: 1em"
>
<div>
<span style="white-space: pre">p(z) = </span
><input
id="poly"
type="text"
value="z**3 - 2*z + 2"
/>
</div>
<div>
<span style="white-space: pre">a = </span
><input
id="coef"
type="text"
value="1"
style="width: 40px"
/>
</div>
<div style="display: flex; flex-direction: row">
<span style="white-space: pre">x = [</span>
<input
id="x0"
type="text"
value="-2.5"
style="width: 80px; text-align: right"
/>
<span style="white-space: pre">, </span>
<input
id="x1"
type="text"
value="2.5"
style="width: 80px; text-align: right"
/>
<span style="white-space: pre">]</span>
</div>
<div style="display: flex; flex-direction: row">
<span style="white-space: pre">y = [</span>
<input
id="y0"
type="text"
value="-5.0"
style="width: 80px; text-align: right"
/>
<span style="white-space: pre">, </span>
<input
id="y1"
type="text"
value="5.0"
style="width: 80px; text-align: right"
/>
<span style="white-space: pre">]</span>
</div>
<div
style="display: flex; flex-direction: row; gap: 1em"
>
<div style="white-space: pre">
<input
type="radio"
id="conv"
name="type"
value="convergence"
checked
/>
convergence
</div>
<div style="white-space: pre">
<input
type="radio"
id="iter"
name="type"
value="iterations"
/>
iterations
</div>
</div>
</fieldset>
<div>
<div class="loading"></div>
<canvas></canvas>
</div>
</div>
</div>
<div style="display: flex; flex-direction: row">
<span style="white-space: pre">x = [</span>
<input
id="x0"
type="text"
value="-2.5"
style="width: 80px; text-align: right"
/>
<span style="white-space: pre">, </span>
<input
id="x1"
type="text"
value="2.5"
style="width: 80px; text-align: right"
/>
<span style="white-space: pre">]</span>
</div>
<div style="display: flex; flex-direction: row">
<span style="white-space: pre">y = [</span>
<input
id="y0"
type="text"
value="-5.0"
style="width: 80px; text-align: right"
/>
<span style="white-space: pre">, </span>
<input
id="y1"
type="text"
value="5.0"
style="width: 80px; text-align: right"
/>
<span style="white-space: pre">]</span>
</div>
<div style="display: flex; flex-direction: row; gap: 1em">
<div style="white-space: pre">
<input
type="radio"
id="conv"
name="type"
value="convergence"
checked
/>
convergence
</div>
<div style="white-space: pre">
<input type="radio" id="iter" name="type" value="iterations" />
iterations
</div>
</div>
</fieldset>
<div>
<div class="loading"></div>
<canvas></canvas>
</div>
</div>
</div>
<py-tutor>
<py-config type="json">
{
"packages": [
"numpy",
"sympy"
],
"fetch": [
{
"files": [
"./palettes.py",
"./fractals.py"
]
}
],
"plugins": [
"../build/plugins/python/py_tutor.py"
]
}
</py-config>
<py-tutor>
<py-config type="json">
{
"packages": [
"numpy",
"sympy"
],
"fetch": [
{
"files": [
"./palettes.py",
"./fractals.py"
]
}
],
"plugins": [
"../build/plugins/python/py_tutor.py"
]
}
</py-config>
<py-script>
from pyodide.ffi import to_js, create_proxy
<py-script>
from pyodide.ffi import to_js, create_proxy
import numpy as np
import sympy
import numpy as np
import sympy
from palettes import Magma256
from fractals import mandelbrot, julia, newton
from palettes import Magma256
from fractals import mandelbrot, julia, newton
from js import (
console,
document,
devicePixelRatio,
ImageData,
Uint8ClampedArray,
CanvasRenderingContext2D as Context2d,
requestAnimationFrame,
)
from js import (
console,
document,
devicePixelRatio,
ImageData,
Uint8ClampedArray,
CanvasRenderingContext2D as Context2d,
requestAnimationFrame,
)
def prepare_canvas(width: int, height: int, canvas: Element) -> Context2d:
ctx = canvas.getContext("2d")
def prepare_canvas(width: int, height: int, canvas: Element) -> Context2d:
ctx = canvas.getContext("2d")
canvas.style.width = f"{width}px"
canvas.style.height = f"{height}px"
canvas.style.width = f"{width}px"
canvas.style.height = f"{height}px"
canvas.width = width
canvas.height = height
canvas.width = width
canvas.height = height
ctx.clearRect(0, 0, width, height)
ctx.clearRect(0, 0, width, height)
return ctx
return ctx
def color_map(array: np.array, palette: np.array) -> np.array:
size, _ = palette.shape
index = (array/array.max()*(size - 1)).round().astype("uint8")
def color_map(array: np.array, palette: np.array) -> np.array:
size, _ = palette.shape
index = (array/array.max()*(size - 1)).round().astype("uint8")
width, height = array.shape
image = np.full((width, height, 4), 0xff, dtype=np.uint8)
image[:, :, :3] = palette[index]
width, height = array.shape
image = np.full((width, height, 4), 0xff, dtype=np.uint8)
image[:, :, :3] = palette[index]
return image
return image
def draw_image(ctx: Context2d, image: np.array) -> None:
data = Uint8ClampedArray.new(to_js(image.tobytes()))
width, height, _ = image.shape
image_data = ImageData.new(data, width, height)
ctx.putImageData(image_data, 0, 0)
def draw_image(ctx: Context2d, image: np.array) -> None:
data = Uint8ClampedArray.new(to_js(image.tobytes()))
width, height, _ = image.shape
image_data = ImageData.new(data, width, height)
ctx.putImageData(image_data, 0, 0)
width, height = 600, 600
width, height = 600, 600
async def draw_mandelbrot() -> None:
spinner = document.querySelector("#mandelbrot .loading")
canvas = document.querySelector("#mandelbrot canvas")
async def draw_mandelbrot() -> None:
spinner = document.querySelector("#mandelbrot .loading")
canvas = document.querySelector("#mandelbrot canvas")
spinner.style.display = ""
canvas.style.display = "none"
spinner.style.display = ""
canvas.style.display = "none"
ctx = prepare_canvas(width, height, canvas)
ctx = prepare_canvas(width, height, canvas)
console.log("Computing Mandelbrot set ...")
console.time("mandelbrot")
iters = mandelbrot(width, height)
console.timeEnd("mandelbrot")
console.log("Computing Mandelbrot set ...")
console.time("mandelbrot")
iters = mandelbrot(width, height)
console.timeEnd("mandelbrot")
image = color_map(iters, Magma256)
draw_image(ctx, image)
image = color_map(iters, Magma256)
draw_image(ctx, image)
spinner.style.display = "none"
canvas.style.display = "block"
spinner.style.display = "none"
canvas.style.display = "block"
async def draw_julia() -> None:
spinner = document.querySelector("#julia .loading")
canvas = document.querySelector("#julia canvas")
async def draw_julia() -> None:
spinner = document.querySelector("#julia .loading")
canvas = document.querySelector("#julia canvas")
spinner.style.display = ""
canvas.style.display = "none"
spinner.style.display = ""
canvas.style.display = "none"
ctx = prepare_canvas(width, height, canvas)
ctx = prepare_canvas(width, height, canvas)
console.log("Computing Julia set ...")
console.time("julia")
iters = julia(width, height)
console.timeEnd("julia")
console.log("Computing Julia set ...")
console.time("julia")
iters = julia(width, height)
console.timeEnd("julia")
image = color_map(iters, Magma256)
draw_image(ctx, image)
image = color_map(iters, Magma256)
draw_image(ctx, image)
spinner.style.display = "none"
canvas.style.display = "block"
spinner.style.display = "none"
canvas.style.display = "block"
def ranges():
x0_in = document.querySelector("#x0")
x1_in = document.querySelector("#x1")
y0_in = document.querySelector("#y0")
y1_in = document.querySelector("#y1")
def ranges():
x0_in = document.querySelector("#x0")
x1_in = document.querySelector("#x1")
y0_in = document.querySelector("#y0")
y1_in = document.querySelector("#y1")
xr = (float(x0_in.value), float(x1_in.value))
yr = (float(y0_in.value), float(y1_in.value))
xr = (float(x0_in.value), float(x1_in.value))
yr = (float(y0_in.value), float(y1_in.value))
return xr, yr
return xr, yr
current_image = None
async def draw_newton() -> None:
spinner = document.querySelector("#newton .loading")
canvas = document.querySelector("#newton canvas")
current_image = None
async def draw_newton() -> None:
spinner = document.querySelector("#newton .loading")
canvas = document.querySelector("#newton canvas")
spinner.style.display = ""
canvas.style.display = "none"
spinner.style.display = ""
canvas.style.display = "none"
ctx = prepare_canvas(width, height, canvas)
ctx = prepare_canvas(width, height, canvas)
console.log("Computing Newton set ...")
console.log("Computing Newton set ...")
poly_in = document.querySelector("#poly")
coef_in = document.querySelector("#coef")
conv_in = document.querySelector("#conv")
iter_in = document.querySelector("#iter")
poly_in = document.querySelector("#poly")
coef_in = document.querySelector("#coef")
conv_in = document.querySelector("#conv")
iter_in = document.querySelector("#iter")
xr, yr = ranges()
xr, yr = ranges()
# z**3 - 1
# z**8 + 15*z**4 - 16
# z**3 - 2*z + 2
# z**3 - 1
# z**8 + 15*z**4 - 16
# z**3 - 2*z + 2
expr = sympy.parse_expr(poly_in.value)
coeffs = [ complex(c) for c in reversed(sympy.Poly(expr, sympy.Symbol("z")).all_coeffs()) ]
poly = np.polynomial.Polynomial(coeffs)
expr = sympy.parse_expr(poly_in.value)
coeffs = [ complex(c) for c in reversed(sympy.Poly(expr, sympy.Symbol("z")).all_coeffs()) ]
poly = np.polynomial.Polynomial(coeffs)
coef = complex(sympy.parse_expr(coef_in.value))
coef = complex(sympy.parse_expr(coef_in.value))
console.time("newton")
iters, roots = newton(width, height, p=poly, a=coef, xr=xr, yr=yr)
console.timeEnd("newton")
console.time("newton")
iters, roots = newton(width, height, p=poly, a=coef, xr=xr, yr=yr)
console.timeEnd("newton")
if conv_in.checked:
n = poly.degree() + 1
k = int(len(Magma256)/n)
if conv_in.checked:
n = poly.degree() + 1
k = int(len(Magma256)/n)
colors = Magma256[::k, :][:n]
colors[0, :] = [255, 0, 0] # red: no convergence
colors = Magma256[::k, :][:n]
colors[0, :] = [255, 0, 0] # red: no convergence
image = color_map(roots, colors)
else:
image = color_map(iters, Magma256)
image = color_map(roots, colors)
else:
image = color_map(iters, Magma256)
global current_image
current_image = image
draw_image(ctx, image)
global current_image
current_image = image
draw_image(ctx, image)
spinner.style.display = "none"
canvas.style.display = "block"
spinner.style.display = "none"
canvas.style.display = "block"
handler = create_proxy(lambda _event: draw_newton())
document.querySelector("#newton fieldset").addEventListener("change", handler)
handler = create_proxy(lambda _event: draw_newton())
document.querySelector("#newton fieldset").addEventListener("change", handler)
canvas = document.querySelector("#newton canvas")
canvas = document.querySelector("#newton canvas")
is_selecting = False
init_sx, init_sy = None, None
sx, sy = None, None
async def mousemove(event):
global is_selecting
global init_sx
global init_sy
global sx
global sy
is_selecting = False
init_sx, init_sy = None, None
sx, sy = None, None
async def mousemove(event):
global is_selecting
global init_sx
global init_sy
global sx
global sy
def invert(sx, source_range, target_range):
source_start, source_end = source_range
target_start, target_end = target_range
factor = (target_end - target_start)/(source_end - source_start)
offset = -(factor * source_start) + target_start
return (sx - offset) / factor
def invert(sx, source_range, target_range):
source_start, source_end = source_range
target_start, target_end = target_range
factor = (target_end - target_start)/(source_end - source_start)
offset = -(factor * source_start) + target_start
return (sx - offset) / factor
bds = canvas.getBoundingClientRect()
event_sx, event_sy = event.clientX - bds.x, event.clientY - bds.y
bds = canvas.getBoundingClientRect()
event_sx, event_sy = event.clientX - bds.x, event.clientY - bds.y
ctx = canvas.getContext("2d")
ctx = canvas.getContext("2d")
pressed = event.buttons == 1
if is_selecting:
if not pressed:
xr, yr = ranges()
pressed = event.buttons == 1
if is_selecting:
if not pressed:
xr, yr = ranges()
x0 = invert(init_sx, xr, (0, width))
x1 = invert(sx, xr, (0, width))
y0 = invert(init_sy, yr, (0, height))
y1 = invert(sy, yr, (0, height))
x0 = invert(init_sx, xr, (0, width))
x1 = invert(sx, xr, (0, width))
y0 = invert(init_sy, yr, (0, height))
y1 = invert(sy, yr, (0, height))
document.querySelector("#x0").value = x0
document.querySelector("#x1").value = x1
document.querySelector("#y0").value = y0
document.querySelector("#y1").value = y1
document.querySelector("#x0").value = x0
document.querySelector("#x1").value = x1
document.querySelector("#y0").value = y0
document.querySelector("#y1").value = y1
is_selecting = False
init_sx, init_sy = None, None
sx, sy = init_sx, init_sy
is_selecting = False
init_sx, init_sy = None, None
sx, sy = init_sx, init_sy
await draw_newton()
else:
ctx.save()
ctx.clearRect(0, 0, width, height)
draw_image(ctx, current_image)
sx, sy = event_sx, event_sy
ctx.beginPath()
ctx.rect(init_sx, init_sy, sx - init_sx, sy - init_sy)
ctx.fillStyle = "rgba(255, 255, 255, 0.4)"
ctx.strokeStyle = "rgba(255, 255, 255, 1.0)"
ctx.fill()
ctx.stroke()
ctx.restore()
else:
if pressed:
is_selecting = True
init_sx, init_sy = event_sx, event_sy
sx, sy = init_sx, init_sy
await draw_newton()
else:
ctx.save()
ctx.clearRect(0, 0, width, height)
draw_image(ctx, current_image)
sx, sy = event_sx, event_sy
ctx.beginPath()
ctx.rect(init_sx, init_sy, sx - init_sx, sy - init_sy)
ctx.fillStyle = "rgba(255, 255, 255, 0.4)"
ctx.strokeStyle = "rgba(255, 255, 255, 1.0)"
ctx.fill()
ctx.stroke()
ctx.restore()
else:
if pressed:
is_selecting = True
init_sx, init_sy = event_sx, event_sy
sx, sy = init_sx, init_sy
canvas.addEventListener("mousemove", create_proxy(mousemove))
canvas.addEventListener("mousemove", create_proxy(mousemove))
import asyncio
import asyncio
async def main():
_ = await asyncio.gather(
draw_mandelbrot(),
draw_julia(),
draw_newton(),
)
async def main():
_ = await asyncio.gather(
draw_mandelbrot(),
draw_julia(),
draw_newton(),
)
asyncio.ensure_future(main())
</py-script>
</py-tutor>
</section>
</body>
asyncio.ensure_future(main())
</py-script>
</py-tutor>
</section>
</body>
</html>

View File

@@ -1,124 +1,132 @@
<!doctype html>
<html>
<head>
<title id="header-title"></title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<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>
<title id="header-title"></title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<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>
<link rel="stylesheet" href="./assets/css/examples.css" />
</head>
<link rel="stylesheet" href="./assets/css/examples.css" />
</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" id="page-title" href="" style="color: #f0ab3c"></a>
</div>
</nav>
<body>
<nav class="navbar" style="background-color: #000000">
<div class="app-header">
<a href="/">
<img src="./logo.png" class="logo" />
</a>
<a
class="title"
id="page-title"
href=""
style="color: #f0ab3c"
></a>
</div>
</nav>
<br />
<div id="page-message"></div>
<br />
<div id="page-message"></div>
<div id="pandas-source">
<h3>Data Source</h3>
<input type="text" id="txt-url" class="py-input" size="70" />
<button
type="submit"
id="btn-load"
class="py-button"
py-click="loadFromURL()"
>
Load CSV
</button>
</div>
<div id="pandas-source">
<h3>Data Source</h3>
<input type="text" id="txt-url" class="py-input" size="70" />
<button
type="submit"
id="btn-load"
class="py-button"
py-click="loadFromURL()"
>
Load CSV
</button>
</div>
<div id="pandas-repl" hidden>
<h3>Python REPL</h3>
<py-repl id="pandas-repl-inner" output="pandas-output-inner">
# Hit SHIFT + ENTER to execute example code # Get all closed airports in
Great Britain df2 = df.query("type == 'closed' & iso_country == 'GB'")
df2
</py-repl>
</div>
<div id="pandas-repl" hidden>
<h3>Python REPL</h3>
<py-repl id="pandas-repl-inner" output="pandas-output-inner">
# Hit SHIFT + ENTER to execute example code # Get all closed
airports in Great Britain df2 = df.query("type == 'closed' &
iso_country == 'GB'") df2
</py-repl>
</div>
<div id="pandas-output" hidden>
<h3>Output</h3>
<div id="pandas-output-inner"></div>
</div>
<div id="pandas-output" hidden>
<h3>Output</h3>
<div id="pandas-output-inner"></div>
</div>
<div id="pandas-dev-console" hidden>
<h3>Dev Console</h3>
<py-terminal auto></py-terminal>
</div>
<div id="pandas-dev-console" hidden>
<h3>Dev Console</h3>
<py-terminal auto></py-terminal>
</div>
<py-tutor>
<py-config>
plugins = [
"../build/plugins/python/py_tutor.py"
]
packages = ["pandas"]
</py-config>
<py-tutor>
<py-config>
plugins = [
"../build/plugins/python/py_tutor.py"
]
packages = ["pandas"]
</py-config>
<section class="pyscript">
<py-script>
import pandas as pd
from pyodide.http import open_url
import sys
<section class="pyscript">
<py-script>
import pandas as pd
from pyodide.http import open_url
import sys
title = "Pandas (and basic DOM manipulation)"
page_message = "This example loads a remote CSV file into a Pandas dataframe, displays it and lets you manipulate it through a Python REPL"
title = "Pandas (and basic DOM manipulation)"
page_message = "This example loads a remote CSV file into a Pandas dataframe, displays it and lets you manipulate it through a Python REPL"
url = "https://raw.githubusercontent.com/datasets/airport-codes/master/data/airport-codes.csv"
url = "https://raw.githubusercontent.com/datasets/airport-codes/master/data/airport-codes.csv"
Element("header-title").element.innerText = title
Element("page-title").element.innerText = title
Element("page-message").element.innerText = page_message
Element("header-title").element.innerText = title
Element("page-title").element.innerText = title
Element("page-message").element.innerText = page_message
Element("txt-url").element.value = url
Element("txt-url").element.value = url
# Depending on the type of DOM element, there are several alternative methods to write to it
# Element("id-of-dom-element").write("example")
# Element("id-of-dom-element").innerText = "example"
# Element("id-of-dom-element").value = "example"
# Element("id-of-dom-element").element.innerText = "example"
# Element("id-of-dom-element").element.value = "example"
# js.document.getElementById("id-of-dom-element").innerText = "example"
# js.document.getElementById("id-of-dom-element").value = "example"
# Depending on the type of DOM element, there are several alternative methods to write to it
# Element("id-of-dom-element").write("example")
# Element("id-of-dom-element").innerText = "example"
# Element("id-of-dom-element").value = "example"
# Element("id-of-dom-element").element.innerText = "example"
# Element("id-of-dom-element").element.value = "example"
# js.document.getElementById("id-of-dom-element").innerText = "example"
# js.document.getElementById("id-of-dom-element").value = "example"
df = pd.DataFrame()
df = pd.DataFrame()
def loadFromURL(*ags, **kws):
global df
def loadFromURL(*ags, **kws):
global df
# clear dataframe & output
df = pd.DataFrame()
Element("pandas-output-inner").element.innerHTML = ""
# clear dataframe & output
df = pd.DataFrame()
Element("pandas-output-inner").element.innerHTML = ""
url = Element("txt-url").element.value
log ("Trying to fetch CSV from " + url)
url = Element("txt-url").element.value
log ("Trying to fetch CSV from " + url)
df = pd.read_csv(open_url(url))
df = pd.read_csv(open_url(url))
Element("pandas-repl").element.style.display = "block"
Element("pandas-output").element.style.display = "block"
Element("pandas-dev-console").element.style.display = "block"
Element("pandas-repl").element.style.display = "block"
Element("pandas-output").element.style.display = "block"
Element("pandas-dev-console").element.style.display = "block"
display (df, target="pandas-output-inner", append="False")
display (df, target="pandas-output-inner", append="False")
def log(message):
# log to pyscript dev console
print (message)
def log(message):
# log to pyscript dev console
print (message)
# log to JS console
js.console.log (message)
</py-script>
</section>
</py-tutor>
</body>
# log to JS console
js.console.log (message)
</py-script>
</section>
</py-tutor>
</body>
</html>

View File

@@ -1,63 +1,68 @@
<html>
<head>
<title>Panel 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-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.jsdelivr.net/npm/@holoviz/panel@0.14.1/dist/panel.min.js"
></script>
<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" />
</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">Panel Example</a>
</div>
</nav>
<section class="pyscript">
<div id="simple_app"></div>
<head>
<title>Panel 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-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.jsdelivr.net/npm/@holoviz/panel@0.14.1/dist/panel.min.js"
></script>
<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" />
</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"
>Panel Example</a
>
</div>
</nav>
<section class="pyscript">
<div id="simple_app"></div>
<py-tutor>
<py-config>
packages = [
"https://cdn.holoviz.org/panel/0.14.3/dist/wheels/bokeh-2.4.3-py3-none-any.whl",
"numpy",
"panel==0.14.1"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-tutor>
<py-config>
packages = [
"https://cdn.holoviz.org/panel/0.14.3/dist/wheels/bokeh-2.4.3-py3-none-any.whl",
"numpy",
"panel==0.14.1"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-script>
import panel as pn
<py-script>
import panel as pn
slider = pn.widgets.FloatSlider(start=0, end=10, name='Amplitude')
slider = pn.widgets.FloatSlider(start=0, end=10, name='Amplitude')
def callback(new):
return f'Amplitude is: {new}'
def callback(new):
return f'Amplitude is: {new}'
pn.Row(slider, pn.bind(callback, slider)).servable(target='simple_app');
</py-script>
</py-tutor>
</section>
</body>
pn.Row(slider, pn.bind(callback, slider)).servable(target='simple_app');
</py-script>
</py-tutor>
</section>
</body>
</html>

View File

@@ -1,281 +1,284 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="theme-color" content="#0072b5" />
<meta name="name" content="PyScript/Panel DeckGL Demo" />
<head>
<meta charset="utf-8" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="theme-color" content="#0072b5" />
<meta name="name" content="PyScript/Panel DeckGL Demo" />
<title>PyScript/Panel DeckGL Demo</title>
<link rel="icon" type="image/x-icon" href="./favicon.png" />
<title>PyScript/Panel DeckGL Demo</title>
<link rel="icon" type="image/x-icon" href="./favicon.png" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
type="text/css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/widgets.css"
type="text/css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/markdown.css"
type="text/css"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
type="text/css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/widgets.css"
type="text/css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/markdown.css"
type="text/css"
/>
<script
type="text/javascript"
src="https://unpkg.com/h3-js@3.7.2/dist/h3-js.umd.js"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/deck.gl@8.6.7/dist.min.js"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/@deck.gl/json@8.6.7/dist.min.js"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/@loaders.gl/csv@3.1.7/dist/dist.min.js"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/@loaders.gl/json@3.1.7/dist/dist.min.js"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/@loaders.gl/3d-tiles@3.1.7/dist/dist.min.js"
></script>
<script
type="text/javascript"
src="https://api.mapbox.com/mapbox-gl-js/v2.6.1/mapbox-gl.js"
></script>
<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-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://unpkg.com/@holoviz/panel@0.13.1/dist/panel.js"
></script>
<script
type="text/javascript"
src="https://unpkg.com/h3-js@3.7.2/dist/h3-js.umd.js"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/deck.gl@8.6.7/dist.min.js"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/@deck.gl/json@8.6.7/dist.min.js"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/@loaders.gl/csv@3.1.7/dist/dist.min.js"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/@loaders.gl/json@3.1.7/dist/dist.min.js"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/@loaders.gl/3d-tiles@3.1.7/dist/dist.min.js"
></script>
<script
type="text/javascript"
src="https://api.mapbox.com/mapbox-gl-js/v2.6.1/mapbox-gl.js"
></script>
<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-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://unpkg.com/@holoviz/panel@0.13.1/dist/panel.js"
></script>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css"
/>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
<style>
#sidebar {
width: 400px;
padding: 0;
}
</style>
<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" />
</head>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
<style>
#sidebar {
width: 400px;
padding: 0;
}
</style>
<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" />
</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"
>Panel DeckGL NYC Taxi Demo</a
>
</div>
</nav>
<section class="pyscript">
<div class="d-flex flex-nowrap" id="content">
<div class="sidenav" id="sidebar">
<ul class="nav flex-column">
<div class="bk-root" id="widgets"></div>
<py-repl id="my-repl" auto-generate="true"> </py-repl>
</ul>
</div>
<div class="col mh-100" style="padding: 0">
<div class="bk-root" id="plot"></div>
</div>
</div>
<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"
>Panel DeckGL NYC Taxi Demo</a
>
</div>
</nav>
<section class="pyscript">
<div class="d-flex flex-nowrap" id="content">
<div class="sidenav" id="sidebar">
<ul class="nav flex-column">
<div class="bk-root" id="widgets"></div>
<py-repl id="my-repl" auto-generate="true"> </py-repl>
</ul>
</div>
<div class="col mh-100" style="padding: 0">
<div class="bk-root" id="plot"></div>
</div>
</div>
<py-tutor>
<py-config>
packages = [
"https://cdn.holoviz.org/panel/0.14.3/dist/wheels/bokeh-2.4.3-py3-none-any.whl",
"numpy",
"pandas",
"panel==0.13.1"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-tutor>
<py-config>
packages = [
"https://cdn.holoviz.org/panel/0.14.3/dist/wheels/bokeh-2.4.3-py3-none-any.whl",
"numpy",
"pandas",
"panel==0.13.1"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-script>
import panel as pn
import pandas as pd
import param
<py-script>
import panel as pn
import pandas as pd
import param
from pyodide.http import open_url
from pyodide.http import open_url
MAPBOX_KEY = "pk.eyJ1IjoicGFuZWxvcmciLCJhIjoiY2s1enA3ejhyMWhmZjNobjM1NXhtbWRrMyJ9.B_frQsAVepGIe-HiOJeqvQ"
MAPBOX_KEY = "pk.eyJ1IjoicGFuZWxvcmciLCJhIjoiY2s1enA3ejhyMWhmZjNobjM1NXhtbWRrMyJ9.B_frQsAVepGIe-HiOJeqvQ"
class App(param.Parameterized):
class App(param.Parameterized):
data = param.DataFrame(precedence=-1)
data = param.DataFrame(precedence=-1)
view = param.DataFrame(precedence=-1)
view = param.DataFrame(precedence=-1)
arc_view = param.DataFrame(precedence=-1)
arc_view = param.DataFrame(precedence=-1)
radius = param.Integer(default=50, bounds=(20, 1000))
radius = param.Integer(default=50, bounds=(20, 1000))
elevation = param.Integer(default=10, bounds=(0, 50))
elevation = param.Integer(default=10, bounds=(0, 50))
hour = param.Integer(default=0, bounds=(0, 23))
hour = param.Integer(default=0, bounds=(0, 23))
speed = param.Integer(default=1, bounds=(0, 10), precedence=-1)
speed = param.Integer(default=1, bounds=(0, 10), precedence=-1)
play = param.Event(label='▷')
play = param.Event(label='▷')
def __init__(self, **params):
self.deck_gl = None
super().__init__(**params)
self.deck_gl = pn.pane.DeckGL(
dict(self.spec),
mapbox_api_key=MAPBOX_KEY,
throttle={'click': 10},
sizing_mode='stretch_both',
margin=0
)
self.deck_gl.param.watch(self._update_arc_view, 'click_state')
self._playing = False
self._cb = pn.state.add_periodic_callback(
self._update_hour, 1000//self.speed, start=False
)
def __init__(self, **params):
self.deck_gl = None
super().__init__(**params)
self.deck_gl = pn.pane.DeckGL(
dict(self.spec),
mapbox_api_key=MAPBOX_KEY,
throttle={'click': 10},
sizing_mode='stretch_both',
margin=0
)
self.deck_gl.param.watch(self._update_arc_view, 'click_state')
self._playing = False
self._cb = pn.state.add_periodic_callback(
self._update_hour, 1000//self.speed, start=False
)
@property
def spec(self):
return {
"initialViewState": {
"bearing": 0,
"latitude": 40.7,
"longitude": -73.9,
"maxZoom": 15,
"minZoom": 5,
"pitch": 40.5,
"zoom": 11
},
"layers": [self.hex_layer, self.arc_layer],
"mapStyle": "mapbox://styles/mapbox/dark-v9",
"views": [
{"@@type": "MapView", "controller": True}
]
}
@property
def spec(self):
return {
"initialViewState": {
"bearing": 0,
"latitude": 40.7,
"longitude": -73.9,
"maxZoom": 15,
"minZoom": 5,
"pitch": 40.5,
"zoom": 11
},
"layers": [self.hex_layer, self.arc_layer],
"mapStyle": "mapbox://styles/mapbox/dark-v9",
"views": [
{"@@type": "MapView", "controller": True}
]
}
@property
def hex_layer(self):
return {
"@@type": "HexagonLayer",
"autoHighlight": True,
"coverage": 1,
"data": self.data if self.view is None else self.view,
"elevationRange": [0, 100],
"elevationScale": self.elevation,
"radius": self.radius,
"extruded": True,
"getPosition": "@@=[pickup_x, pickup_y]",
"id": "8a553b25-ef3a-489c-bbe2-e102d18a3211"
}
@property
def hex_layer(self):
return {
"@@type": "HexagonLayer",
"autoHighlight": True,
"coverage": 1,
"data": self.data if self.view is None else self.view,
"elevationRange": [0, 100],
"elevationScale": self.elevation,
"radius": self.radius,
"extruded": True,
"getPosition": "@@=[pickup_x, pickup_y]",
"id": "8a553b25-ef3a-489c-bbe2-e102d18a3211"
}
@property
def arc_layer(self):
return {
"@@type": "ArcLayer",
"id": 'arc-layer',
"data": self.arc_view,
"pickable": True,
"getWidth": 1,
"getSourcePosition": "@@=[pickup_x, pickup_y]",
"getTargetPosition": "@@=[dropoff_x, dropoff_y]",
"getSourceColor": [0, 255, 0, 180],
"getTargetColor": [240, 100, 0, 180]
}
@property
def arc_layer(self):
return {
"@@type": "ArcLayer",
"id": 'arc-layer',
"data": self.arc_view,
"pickable": True,
"getWidth": 1,
"getSourcePosition": "@@=[pickup_x, pickup_y]",
"getTargetPosition": "@@=[dropoff_x, dropoff_y]",
"getSourceColor": [0, 255, 0, 180],
"getTargetColor": [240, 100, 0, 180]
}
def _update_hour(self):
self.hour = (self.hour+1) % 24
def _update_hour(self):
self.hour = (self.hour+1) % 24
@param.depends('view', watch=True)
def _update_arc_view(self, event=None):
data = self.data if self.view is None else self.view
if not self.deck_gl or not self.deck_gl.click_state:
self.arc_view = data.iloc[:0]
return
lon, lat = self.deck_gl.click_state['coordinate']
tol = 0.001
self.arc_view = data[
(df.pickup_x>=float(lon-tol)) &
(df.pickup_x<=float(lon+tol)) &
(df.pickup_y>=float(lat-tol)) &
(df.pickup_y<=float(lat+tol))
]
@param.depends('view', watch=True)
def _update_arc_view(self, event=None):
data = self.data if self.view is None else self.view
if not self.deck_gl or not self.deck_gl.click_state:
self.arc_view = data.iloc[:0]
return
lon, lat = self.deck_gl.click_state['coordinate']
tol = 0.001
self.arc_view = data[
(df.pickup_x>=float(lon-tol)) &
(df.pickup_x<=float(lon+tol)) &
(df.pickup_y>=float(lat-tol)) &
(df.pickup_y<=float(lat+tol))
]
@param.depends('hour', watch=True, on_init=True)
def _update_hourly_view(self):
self.view = self.data[self.data.hour==self.hour]
@param.depends('hour', watch=True, on_init=True)
def _update_hourly_view(self):
self.view = self.data[self.data.hour==self.hour]
@param.depends('speed', watch=True)
def _update_speed(self):
self._cb.period = 1000//self.speed
@param.depends('speed', watch=True)
def _update_speed(self):
self._cb.period = 1000//self.speed
@param.depends('play', watch=True)
def _play_pause(self):
if self._playing:
self._cb.stop()
self.param.play.label = '▷'
self.param.speed.precedence = -1
else:
self._cb.start()
self.param.play.label = '❚❚'
self.param.speed.precedence = 1
self._playing = not self._playing
@param.depends('play', watch=True)
def _play_pause(self):
if self._playing:
self._cb.stop()
self.param.play.label = '▷'
self.param.speed.precedence = -1
else:
self._cb.start()
self.param.play.label = '❚❚'
self.param.speed.precedence = 1
self._playing = not self._playing
@param.depends('view', 'radius', 'elevation', 'arc_view', watch=True)
def update_spec(self):
self.deck_gl.object = dict(self.spec)
@param.depends('view', 'radius', 'elevation', 'arc_view', watch=True)
def update_spec(self):
self.deck_gl.object = dict(self.spec)
url = 'https://s3.eu-west-1.amazonaws.com/assets.holoviews.org/data/nyc_taxi_wide.csv'
df = pd.read_csv(open_url(url))
app = App(data=df)
controls = pn.Param(app.param, sizing_mode='stretch_width', show_name=False)
url = 'https://s3.eu-west-1.amazonaws.com/assets.holoviews.org/data/nyc_taxi_wide.csv'
df = pd.read_csv(open_url(url))
app = App(data=df)
controls = pn.Param(app.param, sizing_mode='stretch_width', show_name=False)
app.deck_gl.servable(target='plot')
controls.servable(target='widgets');
</py-script>
</py-tutor>
</section>
</body>
app.deck_gl.servable(target='plot')
controls.servable(target='widgets');
</py-script>
</py-tutor>
</section>
</body>
</html>

View File

@@ -1,226 +1,229 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="theme-color" content="#000000" />
<meta name="name" content="PyScript/Panel KMeans Demo" />
<head>
<meta charset="utf-8" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="theme-color" content="#000000" />
<meta name="name" content="PyScript/Panel KMeans Demo" />
<title>Pyscript/Panel KMeans Demo</title>
<link rel="icon" type="image/x-icon" href="./favicon.png" />
<title>Pyscript/Panel KMeans Demo</title>
<link rel="icon" type="image/x-icon" href="./favicon.png" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
type="text/css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/widgets.css"
type="text/css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/markdown.css"
type="text/css"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
type="text/css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/widgets.css"
type="text/css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/markdown.css"
type="text/css"
/>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/vega@5"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/vega-lite@5"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/vega-embed@6"
></script>
<script
type="text/javascript"
src="https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js"
></script>
<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-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://unpkg.com/@holoviz/panel@0.13.1/dist/panel.min.js"
></script>
<script type="text/javascript">
Bokeh.set_log_level("info");
</script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/vega@5"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/vega-lite@5"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/vega-embed@6"
></script>
<script
type="text/javascript"
src="https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js"
></script>
<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-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://unpkg.com/@holoviz/panel@0.13.1/dist/panel.min.js"
></script>
<script type="text/javascript">
Bokeh.set_log_level("info");
</script>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css"
/>
<style>
#sidebar {
width: 350px;
}
</style>
<style>
#sidebar {
width: 350px;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
<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" />
</head>
<link
rel="stylesheet"
href="https://pyscript.net/latest/pyscript.css"
/>
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
</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"
>Panel KMeans Clustering Demo</a
>
</div>
</nav>
<section class="pyscript">
<div class="row overflow-hidden" id="content">
<div class="sidenav" id="sidebar">
<ul class="nav flex-column">
<div class="bk-root" id="x-widget"></div>
<div class="bk-root" id="y-widget"></div>
<div class="bk-root" id="n-widget"></div>
</ul>
</div>
<div class="col mh-100 float-left" id="main">
<div class="bk-root" id="intro"></div>
<div class="bk-root" id="cluster-plot"></div>
<div class="bk-root" id="table"></div>
</div>
</div>
<py-tutor>
<py-config>
packages = [
"https://cdn.holoviz.org/panel/0.14.3/dist/wheels/bokeh-2.4.3-py3-none-any.whl",
"altair",
"numpy",
"pandas",
"scikit-learn",
"panel==0.13.1"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<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"
>Panel KMeans Clustering Demo</a
>
</div>
</nav>
<section class="pyscript">
<div class="row overflow-hidden" id="content">
<div class="sidenav" id="sidebar">
<ul class="nav flex-column">
<div class="bk-root" id="x-widget"></div>
<div class="bk-root" id="y-widget"></div>
<div class="bk-root" id="n-widget"></div>
</ul>
</div>
<div class="col mh-100 float-left" id="main">
<div class="bk-root" id="intro"></div>
<div class="bk-root" id="cluster-plot"></div>
<div class="bk-root" id="table"></div>
</div>
</div>
<py-tutor>
<py-config>
packages = [
"https://cdn.holoviz.org/panel/0.14.3/dist/wheels/bokeh-2.4.3-py3-none-any.whl",
"altair",
"numpy",
"pandas",
"scikit-learn",
"panel==0.13.1"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-script>
import altair as alt
import panel as pn
import pandas as pd
<py-script>
import altair as alt
import panel as pn
import pandas as pd
from sklearn.cluster import KMeans
from pyodide.http import open_url
from sklearn.cluster import KMeans
from pyodide.http import open_url
pn.config.sizing_mode = 'stretch_width'
pn.config.sizing_mode = 'stretch_width'
url = 'https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-07-28/penguins.csv'
penguins = pd.read_csv(open_url(url)).dropna()
cols = list(penguins.columns)[2:6]
url = 'https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-07-28/penguins.csv'
penguins = pd.read_csv(open_url(url)).dropna()
cols = list(penguins.columns)[2:6]
x = pn.widgets.Select(name='x', options=cols, value='bill_depth_mm').servable(target='x-widget')
y = pn.widgets.Select(name='y', options=cols, value='bill_length_mm').servable(target='y-widget')
n_clusters = pn.widgets.IntSlider(name='n_clusters', start=1, end=5, value=3).servable(target='n-widget')
x = pn.widgets.Select(name='x', options=cols, value='bill_depth_mm').servable(target='x-widget')
y = pn.widgets.Select(name='y', options=cols, value='bill_length_mm').servable(target='y-widget')
n_clusters = pn.widgets.IntSlider(name='n_clusters', start=1, end=5, value=3).servable(target='n-widget')
brush = alt.selection_interval(name='brush') # selection of type "interval"
brush = alt.selection_interval(name='brush') # selection of type "interval"
def get_clusters(n_clusters):
kmeans = KMeans(n_clusters=n_clusters)
est = kmeans.fit(penguins[cols].values)
df = penguins.copy()
df['labels'] = est.labels_.astype('str')
return df
def get_clusters(n_clusters):
kmeans = KMeans(n_clusters=n_clusters)
est = kmeans.fit(penguins[cols].values)
df = penguins.copy()
df['labels'] = est.labels_.astype('str')
return df
def get_chart(x, y, df):
centers = df.groupby('labels').mean()
return (
alt.Chart(df)
.mark_point(size=100)
.encode(
x=alt.X(x, scale=alt.Scale(zero=False)),
y=alt.Y(y, scale=alt.Scale(zero=False)),
shape='labels',
color='species'
).add_selection(brush).properties(width=800) +
alt.Chart(centers)
.mark_point(size=250, shape='cross', color='black')
.encode(x=x+':Q', y=y+':Q')
)
def get_chart(x, y, df):
centers = df.groupby('labels').mean()
return (
alt.Chart(df)
.mark_point(size=100)
.encode(
x=alt.X(x, scale=alt.Scale(zero=False)),
y=alt.Y(y, scale=alt.Scale(zero=False)),
shape='labels',
color='species'
).add_selection(brush).properties(width=800) +
alt.Chart(centers)
.mark_point(size=250, shape='cross', color='black')
.encode(x=x+':Q', y=y+':Q')
)
intro = pn.pane.Markdown("""
This app provides an example of **building a simple dashboard using
Panel**.\n\nIt demonstrates how to take the output of **k-means
clustering on the Penguins dataset** using scikit-learn,
parameterizing the number of clusters and the variables to
plot.\n\nThe plot and the table are linked, i.e. selecting on the plot
will filter the data in the table.\n\n The **`x` marks the center** of
the cluster.
""").servable(target='intro')
intro = pn.pane.Markdown("""
This app provides an example of **building a simple dashboard using
Panel**.\n\nIt demonstrates how to take the output of **k-means
clustering on the Penguins dataset** using scikit-learn,
parameterizing the number of clusters and the variables to
plot.\n\nThe plot and the table are linked, i.e. selecting on the plot
will filter the data in the table.\n\n The **`x` marks the center** of
the cluster.
""").servable(target='intro')
chart = pn.pane.Vega().servable(target='cluster-plot')
table = pn.widgets.Tabulator(pagination='remote', page_size=10).servable(target='table')
chart = pn.pane.Vega().servable(target='cluster-plot')
table = pn.widgets.Tabulator(pagination='remote', page_size=10).servable(target='table')
def update_table(event=None):
table.value = get_clusters(n_clusters.value)
def update_table(event=None):
table.value = get_clusters(n_clusters.value)
n_clusters.param.watch(update_table, 'value')
n_clusters.param.watch(update_table, 'value')
@pn.depends(x, y, n_clusters, watch=True)
def update_chart(*events):
chart.object = get_chart(x.value, y.value, table.value)
chart.selection.param.watch(update_filters, 'brush')
@pn.depends(x, y, n_clusters, watch=True)
def update_chart(*events):
chart.object = get_chart(x.value, y.value, table.value)
chart.selection.param.watch(update_filters, 'brush')
def update_filters(event=None):
filters = []
for k, v in (getattr(event, 'new') or {}).items():
filters.append(dict(field=k, type='>=', value=v[0]))
filters.append(dict(field=k, type='<=', value=v[1]))
table.filters = filters
def update_filters(event=None):
filters = []
for k, v in (getattr(event, 'new') or {}).items():
filters.append(dict(field=k, type='>=', value=v[0]))
filters.append(dict(field=k, type='<=', value=v[1]))
table.filters = filters
update_table()
update_chart()
</py-script>
</py-tutor>
</section>
<script>
$(document).ready(function () {
$("#sidebarCollapse").on("click", function () {
$("#sidebar").toggleClass("active");
$(this).toggleClass("active");
var interval = setInterval(function () {
window.dispatchEvent(new Event("resize"));
}, 10);
setTimeout(function () {
clearInterval(interval);
}, 210);
});
});
</script>
</body>
update_table()
update_chart()
</py-script>
</py-tutor>
</section>
<script>
$(document).ready(function () {
$("#sidebarCollapse").on("click", function () {
$("#sidebar").toggleClass("active");
$(this).toggleClass("active");
var interval = setInterval(function () {
window.dispatchEvent(new Event("resize"));
}, 10);
setTimeout(function () {
clearInterval(interval);
}, 210);
});
});
</script>
</body>
</html>

View File

@@ -1,157 +1,162 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="theme-color" content="#000000" />
<meta name="name" content="PyScript/Panel Streaming Demo" />
<head>
<meta charset="utf-8" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="theme-color" content="#000000" />
<meta name="name" content="PyScript/Panel Streaming Demo" />
<title>PyScript/Panel Streaming Demo</title>
<link rel="icon" type="image/x-icon" href="./favicon.ico" />
<title>PyScript/Panel Streaming Demo</title>
<link rel="icon" type="image/x-icon" href="./favicon.ico" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
type="text/css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/widgets.css"
type="text/css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/markdown.css"
type="text/css"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
type="text/css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/widgets.css"
type="text/css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/markdown.css"
type="text/css"
/>
<script
type="text/javascript"
src="https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js"
></script>
<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-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://unpkg.com/@holoviz/panel@0.13.1/dist/panel.min.js"
></script>
<script type="text/javascript">
Bokeh.set_log_level("info");
</script>
<script
type="text/javascript"
src="https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js"
></script>
<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-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://unpkg.com/@holoviz/panel@0.13.1/dist/panel.min.js"
></script>
<script type="text/javascript">
Bokeh.set_log_level("info");
</script>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css"
/>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
<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" />
</head>
<link
rel="stylesheet"
href="https://pyscript.net/latest/pyscript.css"
/>
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
</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">Panel Streaming Demo</a>
</div>
</nav>
<section class="pyscript">
<div class="row overflow-hidden" id="content">
<div class="col mh-100 float-left" id="main">
<div class="bk-root" id="controls"></div>
<div class="row">
<div class="bk-root" id="table"></div>
<div class="bk-root" id="plot"></div>
</div>
</div>
</div>
<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"
>Panel Streaming Demo</a
>
</div>
</nav>
<section class="pyscript">
<div class="row overflow-hidden" id="content">
<div class="col mh-100 float-left" id="main">
<div class="bk-root" id="controls"></div>
<div class="row">
<div class="bk-root" id="table"></div>
<div class="bk-root" id="plot"></div>
</div>
</div>
</div>
<py-tutor>
<py-config>
packages = [
"https://cdn.holoviz.org/panel/0.14.3/dist/wheels/bokeh-2.4.3-py3-none-any.whl",
"numpy",
"pandas",
"panel==0.13.1"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-tutor>
<py-config>
packages = [
"https://cdn.holoviz.org/panel/0.14.3/dist/wheels/bokeh-2.4.3-py3-none-any.whl",
"numpy",
"pandas",
"panel==0.13.1"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
</py-config>
<py-script>
import panel as pn
import numpy as np
import pandas as pd
<py-script>
import panel as pn
import numpy as np
import pandas as pd
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
df = pd.DataFrame(np.random.randn(10, 4), columns=list('ABCD')).cumsum()
df = pd.DataFrame(np.random.randn(10, 4), columns=list('ABCD')).cumsum()
rollover = pn.widgets.IntInput(name='Rollover', value=15)
follow = pn.widgets.Checkbox(name='Follow', value=True, align='end')
rollover = pn.widgets.IntInput(name='Rollover', value=15)
follow = pn.widgets.Checkbox(name='Follow', value=True, align='end')
tabulator = pn.widgets.Tabulator(df, height=450, width=400).servable(target='table')
tabulator = pn.widgets.Tabulator(df, height=450, width=400).servable(target='table')
def color_negative_red(val):
"""
Takes a scalar and returns a string with
the css property `'color: red'` for negative
strings, black otherwise.
"""
color = 'red' if val < 0 else 'green'
return 'color: %s' % color
def color_negative_red(val):
"""
Takes a scalar and returns a string with
the css property `'color: red'` for negative
strings, black otherwise.
"""
color = 'red' if val < 0 else 'green'
return 'color: %s' % color
tabulator.style.applymap(color_negative_red)
tabulator.style.applymap(color_negative_red)
p = figure(height=450, width=600)
p = figure(height=450, width=600)
cds = ColumnDataSource(data=ColumnDataSource.from_df(df))
cds = ColumnDataSource(data=ColumnDataSource.from_df(df))
p.line('index', 'A', source=cds, line_color='red')
p.line('index', 'B', source=cds, line_color='green')
p.line('index', 'C', source=cds, line_color='blue')
p.line('index', 'D', source=cds, line_color='purple')
p.line('index', 'A', source=cds, line_color='red')
p.line('index', 'B', source=cds, line_color='green')
p.line('index', 'C', source=cds, line_color='blue')
p.line('index', 'D', source=cds, line_color='purple')
def stream():
data = df.iloc[-1] + np.random.randn(4)
tabulator.stream(data, rollover=rollover.value, follow=follow.value)
value = {k: [v] for k, v in tabulator.value.iloc[-1].to_dict().items()}
value['index'] = [tabulator.value.index[-1]]
cds.stream(value)
def stream():
data = df.iloc[-1] + np.random.randn(4)
tabulator.stream(data, rollover=rollover.value, follow=follow.value)
value = {k: [v] for k, v in tabulator.value.iloc[-1].to_dict().items()}
value['index'] = [tabulator.value.index[-1]]
cds.stream(value)
cb = pn.state.add_periodic_callback(stream, 200)
cb = pn.state.add_periodic_callback(stream, 200)
pn.pane.Bokeh(p).servable(target='plot')
pn.Row(cb.param.period, rollover, follow, width=400).servable(target='controls')
</py-script>
</py-tutor>
</section>
</body>
pn.pane.Bokeh(p).servable(target='plot')
pn.Row(cb.param.period, rollover, follow, width=400).servable(target='controls')
</py-script>
</py-tutor>
</section>
</body>
</html>

View File

@@ -1,16 +1,16 @@
#output > div {
font-family: "monospace";
background-color: #e5e5e5;
border: 1px solid lightgray;
border-top: 0;
font-size: 0.875rem;
padding: 0.5rem;
font-family: "monospace";
background-color: #e5e5e5;
border: 1px solid lightgray;
border-top: 0;
font-size: 0.875rem;
padding: 0.5rem;
}
#output > div:first-child {
border-top: 1px solid lightgray;
border-top: 1px solid lightgray;
}
#output > div:nth-child(even) {
border: 0;
border: 0;
}

View File

@@ -1,42 +1,47 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>REPL</title>
<title>REPL</title>
<link rel="icon" type="image/png" href="favicon.png" />
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
</head>
<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>
<link rel="stylesheet" href="./assets/css/examples.css" />
</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">PyScript REPL</a>
</div>
</nav>
<section class="pyscript">
<h1><b>PyScript REPL</b></h1>
Tip: press Shift-ENTER to evaluate a cell
<br />
<py-tutor modules="antigravity.py">
<py-config>
plugins = [
"../build/plugins/python/py_tutor.py"
]
[[fetch]]
files = ["./antigravity.py"]
</py-config>
<div style="margin-right: 3rem">
<py-repl id="my-repl" auto-generate="true"> </py-repl>
</div>
</py-tutor>
</section>
</body>
<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"
>PyScript REPL</a
>
</div>
</nav>
<section class="pyscript">
<h1><b>PyScript REPL</b></h1>
Tip: press Shift-ENTER to evaluate a cell
<br />
<py-tutor modules="antigravity.py">
<py-config>
plugins = [
"../build/plugins/python/py_tutor.py"
]
[[fetch]]
files = ["./antigravity.py"]
</py-config>
<div style="margin-right: 3rem">
<py-repl id="my-repl" auto-generate="true"> </py-repl>
</div>
</py-tutor>
</section>
</body>
</html>

View File

@@ -1,47 +1,50 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Custom REPL Example</title>
<title>Custom REPL Example</title>
<link rel="icon" type="image/png" href="favicon.png" />
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<link rel="stylesheet" href="repl.css" />
<link rel="stylesheet" href="./assets/css/examples.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head>
<link rel="icon" type="image/png" href="favicon.png" />
<link
rel="stylesheet"
href="https://pyscript.net/latest/pyscript.css"
/>
<link rel="stylesheet" href="repl.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">Custom REPL</a>
</div>
</nav>
<section class="pyscript">
<h1 class="font-semibold text-2xl ml-5">Custom REPL</h1>
<py-tutor modules="antigravity.py">
<py-config>
packages = [
"bokeh",
"numpy"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
<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">Custom REPL</a>
</div>
</nav>
<section class="pyscript">
<h1 class="font-semibold text-2xl ml-5">Custom REPL</h1>
<py-tutor modules="antigravity.py">
<py-config>
packages = [
"bokeh",
"numpy"
]
plugins = [
"../build/plugins/python/py_tutor.py"
]
[[fetch]]
files = ["./utils.py", "./antigravity.py"]
</py-config>
<div style="margin-right: 3rem">
<py-repl id="my-repl" auto-generate="true"> </py-repl>
<div id="output" class="p-4"></div>
</div>
</py-tutor>
</section>
</body>
[[fetch]]
files = ["./utils.py", "./antigravity.py"]
</py-config>
<div style="margin-right: 3rem">
<py-repl id="my-repl" auto-generate="true"> </py-repl>
<div id="output" class="p-4"></div>
</div>
</py-tutor>
</section>
</body>
</html>

View File

@@ -1,172 +1,179 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>PyScript — Simple Bioinformatics Example</title>
<link rel="icon" type="image/x-icon" href="./favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="stylesheet"
type="text/css"
media="screen"
href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css"
/>
<link
rel="icon"
type="image/png"
href="https://user-images.githubusercontent.com/49681382/166738771-d0c26557-426c-4688-9641-8db5e6b08348.png"
/>
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head>
<body>
<!-- Header -->
<section class="hero is-primary is-small">
<div class="hero-body">
<p class="title is-3">
PyScript — Simple Bioinformatics Example
<span class="tag is-white">v.1</span>
</p>
<p class="subtitle is-6">
Demonstrates the simple use of
<a href="https://pyscript.net/" target="_blank"
><code>PyScript</code></a
>
in <strong>Bioinformatics/Computational Biology</strong> fields!
</p>
</div>
</section>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>PyScript — Simple Bioinformatics Example</title>
<link rel="icon" type="image/x-icon" href="./favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="stylesheet"
type="text/css"
media="screen"
href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css"
/>
<link
rel="icon"
type="image/png"
href="https://user-images.githubusercontent.com/49681382/166738771-d0c26557-426c-4688-9641-8db5e6b08348.png"
/>
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head>
<body>
<!-- Header -->
<section class="hero is-primary is-small">
<div class="hero-body">
<p class="title is-3">
PyScript — Simple Bioinformatics Example
<span class="tag is-white">v.1</span>
</p>
<p class="subtitle is-6">
Demonstrates the simple use of
<a href="https://pyscript.net/" target="_blank"
><code>PyScript</code></a
>
in
<strong>Bioinformatics/Computational Biology</strong>
fields!
</p>
</div>
</section>
<!-- Main Content -->
<div class="container is-white is-fluid" style="margin-top: 45px">
<p class="title is-3">🧬 DNA Sequence Tool</p>
<!-- Main Content -->
<div class="container is-white is-fluid" style="margin-top: 45px">
<p class="title is-3">🧬 DNA Sequence Tool</p>
<!--- DNA Sequence Input -->
<div class="field">
<label class="label">Input DNA Sequence</label>
<div class="control">
<textarea
class="textarea"
placeholder="GATTACA"
id="dna_seq"
></textarea>
<!--- DNA Sequence Input -->
<div class="field">
<label class="label">Input DNA Sequence</label>
<div class="control">
<textarea
class="textarea"
placeholder="GATTACA"
id="dna_seq"
></textarea>
</div>
</div>
<!-- Operation Selection -->
<label class="label">Pick the operation to be applied</label>
<div class="field has-addons">
<div class="control is-expanded">
<div class="select is-fullwidth">
<select name="operation" id="operation">
<option value="Reverse">
Compute the reverse counterpart
</option>
<option value="Complement">
Compute the complement counterpart
</option>
<option value="ReverseComplement">
Compute the reverse complement counterpart
</option>
</select>
</div>
</div>
<div class="control">
<button
id="run"
type="button"
class="button is-primary"
py-onClick="run()"
>
Run!
</button>
<button
id="clear"
type="button"
class="button is-danger"
py-onClick="clear()"
>
Clear
</button>
</div>
</div>
<hr />
<!--- DNA Sequence Output -->
<label class="label"
>Output for the
<code id="operation_name_output">given operation</code></label
>
<div id="output"></div>
</div>
</div>
<!-- Operation Selection -->
<label class="label">Pick the operation to be applied</label>
<div class="field has-addons">
<div class="control is-expanded">
<div class="select is-fullwidth">
<select name="operation" id="operation">
<option value="Reverse">Compute the reverse counterpart</option>
<option value="Complement">
Compute the complement counterpart
</option>
<option value="ReverseComplement">
Compute the reverse complement counterpart
</option>
</select>
</div>
</div>
<div class="control">
<button
id="run"
type="button"
class="button is-primary"
py-onClick="run()"
>
Run!
</button>
<button
id="clear"
type="button"
class="button is-danger"
py-onClick="clear()"
>
Clear
</button>
</div>
</div>
<br /><br />
<!-- Footer -->
<footer class="footer">
<div class="content has-text-centered">
<p>
Developed by
<a href="mailto:furkanmtorun@gmail.com"
><strong>Furkan M. Torun (@furkanmtorun)</strong></a
>
<br />
<a href="https://github.com/furkanmtorun">GitHub</a>
|
<a
href="https://scholar.google.com/citations?user=d5ZyOZ4AAAAJ"
>Google Scholar</a
>
| <a href="https://twitter.com/furkanmtorun">Twitter</a> |
<a href="https://www.linkedin.com/in/furkanmtorun/"
>LinkedIn</a
>
</p>
</div>
</footer>
<hr />
<py-script>
# Define HTML elements and inputs
dna_alphabet = "ATGC"
output = Element("output")
dna_seq_element = Element("dna_seq")
operation_element = Element("operation")
operation_name_output_element = Element("operation_name_output")
<!--- DNA Sequence Output -->
<label class="label"
>Output for the
<code id="operation_name_output">given operation</code></label
>
<div id="output"></div>
</div>
# DNA Sequene Operations
def return_reverse(dna_seq):
return dna_seq[::-1]
def return_complement(dna_seq):
return dna_seq.translate(str.maketrans("ATCG", "TAGC"))
def return_reverse_complement(dna_seq):
return dna_seq.translate(str.maketrans("ATCG", "TAGC"))[::-1]
<br /><br />
<!-- Footer -->
<footer class="footer">
<div class="content has-text-centered">
<p>
Developed by
<a href="mailto:furkanmtorun@gmail.com"
><strong>Furkan M. Torun (@furkanmtorun)</strong></a
>
<br />
<a href="https://github.com/furkanmtorun">GitHub</a>
|
<a href="https://scholar.google.com/citations?user=d5ZyOZ4AAAAJ"
>Google Scholar</a
>
| <a href="https://twitter.com/furkanmtorun">Twitter</a> |
<a href="https://www.linkedin.com/in/furkanmtorun/">LinkedIn</a>
</p>
</div>
</footer>
# Check DNA seq is valid
def check_dna_seq(dna_seq):
return all(letter in dna_alphabet for letter in dna_seq.upper())
<py-script>
# Define HTML elements and inputs
dna_alphabet = "ATGC"
output = Element("output")
dna_seq_element = Element("dna_seq")
operation_element = Element("operation")
operation_name_output_element = Element("operation_name_output")
# Clear the form and output
def clear(*args, **kwargs):
dna_seq_element.clear()
output.clear()
# DNA Sequene Operations
def return_reverse(dna_seq):
return dna_seq[::-1]
def return_complement(dna_seq):
return dna_seq.translate(str.maketrans("ATCG", "TAGC"))
def return_reverse_complement(dna_seq):
return dna_seq.translate(str.maketrans("ATCG", "TAGC"))[::-1]
# Run
def run(*args, **kwargs):
dna_seq = dna_seq_element.value
is_dna_seq_valid = check_dna_seq(dna_seq)
if is_dna_seq_valid:
operation_name = operation_element.value
operation_name_output_element.write(operation_name)
# Check DNA seq is valid
def check_dna_seq(dna_seq):
return all(letter in dna_alphabet for letter in dna_seq.upper())
# Compute the desired outputs
if operation_name == "Reverse":
output_dna_seq = return_reverse(dna_seq)
elif operation_name == "Complement":
output_dna_seq = return_complement(dna_seq)
elif operation_name == "ReverseComplement":
output_dna_seq = return_reverse_complement(dna_seq)
# Clear the form and output
def clear(*args, **kwargs):
dna_seq_element.clear()
output.clear()
# Run
def run(*args, **kwargs):
dna_seq = dna_seq_element.value
is_dna_seq_valid = check_dna_seq(dna_seq)
if is_dna_seq_valid:
operation_name = operation_element.value
operation_name_output_element.write(operation_name)
# Compute the desired outputs
if operation_name == "Reverse":
output_dna_seq = return_reverse(dna_seq)
elif operation_name == "Complement":
output_dna_seq = return_complement(dna_seq)
elif operation_name == "ReverseComplement":
output_dna_seq = return_reverse_complement(dna_seq)
# Output the result
output.write(output_dna_seq)
elif (dna_seq.strip() == "") or (dna_seq is None):
output.write("No DNA sequence provided")
else:
output.write("Invalid DNA sequence entered")
</py-script>
</body>
# Output the result
output.write(output_dna_seq)
elif (dna_seq.strip() == "") or (dna_seq is None):
output.write("No DNA sequence provided")
else:
output.write("Invalid DNA sequence entered")
</py-script>
</body>
</html>

View File

@@ -1,64 +1,69 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Simple Clock Demo</title>
<title>Simple Clock Demo</title>
<link rel="icon" type="image/png" href="favicon.png" />
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<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>
<link rel="stylesheet" href="./assets/css/examples.css" />
</head>
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
</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 Clock</a>
</div>
</nav>
<section class="pyscript">
<div class="font-mono">start time: <label id="outputDiv"></label></div>
<div id="outputDiv2" class="font-mono"></div>
<div id="outputDiv3" class="font-mono"></div>
<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 Clock</a>
</div>
</nav>
<section class="pyscript">
<div class="font-mono">
start time: <label id="outputDiv"></label>
</div>
<div id="outputDiv2" class="font-mono"></div>
<div id="outputDiv3" class="font-mono"></div>
<py-tutor modules="utils.py">
<py-config>
plugins = [
"../build/plugins/python/py_tutor.py"
]
[[fetch]]
files = ["./utils.py"]
</py-config>
<py-script>
import utils
display(utils.now())
</py-script>
<py-tutor modules="utils.py">
<py-config>
plugins = [
"../build/plugins/python/py_tutor.py"
]
[[fetch]]
files = ["./utils.py"]
</py-config>
<py-script>
import utils
display(utils.now())
</py-script>
<py-script>
from utils import now
import asyncio
<py-script>
from utils import now
import asyncio
async def foo():
while True:
await asyncio.sleep(1)
output = now()
Element("outputDiv2").write(output)
async def foo():
while True:
await asyncio.sleep(1)
output = now()
Element("outputDiv2").write(output)
out3 = Element("outputDiv3")
if output[-1] in ["0", "4", "8"]:
out3.write("It's espresso time!")
else:
out3.clear()
out3 = Element("outputDiv3")
if output[-1] in ["0", "4", "8"]:
out3.write("It's espresso time!")
else:
out3.clear()
pyscript.run_until_complete(foo())
</py-script>
</py-tutor>
</section>
</body>
pyscript.run_until_complete(foo())
</py-script>
</py-tutor>
</section>
</body>
</html>

View File

@@ -1,84 +1,91 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<head>
<meta charset="utf-8" />
<title>Todo App</title>
<title>Todo App</title>
<link rel="icon" type="image/png" href="favicon.png" />
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<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>
<link rel="stylesheet" href="./assets/css/examples.css" />
</head>
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
</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"
>Pyscript Native TODO App</a
>
</div>
</nav>
<section class="pyscript">
<h1>To Do List</h1>
<py-tutor modules="utils.py;pylist.py">
<py-register-widget
src="./pylist.py"
name="py-list"
klass="PyList"
></py-register-widget>
<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"
>Pyscript Native TODO App</a
>
</div>
</nav>
<section class="pyscript">
<h1>To Do List</h1>
<py-tutor modules="utils.py;pylist.py">
<py-register-widget
src="./pylist.py"
name="py-list"
klass="PyList"
></py-register-widget>
<py-config>
plugins = [
"../build/plugins/python/py_tutor.py"
]
[[fetch]]
files = ["./utils.py", "./pylist.py"]
</py-config>
<py-config>
plugins = [
"../build/plugins/python/py_tutor.py"
]
[[fetch]]
files = ["./utils.py", "./pylist.py"]
</py-config>
<py-script>
from js import document
from pyodide.ffi.wrappers import add_event_listener
<py-script>
from js import document
from pyodide.ffi.wrappers import add_event_listener
def add_task(*ags, **kws):
# create a new dictionary representing the new task
new_task_content = Element("new-task-content")
task = { "content": new_task_content.value, "done": False, "created_at": dt.now() }
def add_task(*ags, **kws):
# create a new dictionary representing the new task
new_task_content = Element("new-task-content")
task = { "content": new_task_content.value, "done": False, "created_at": dt.now() }
# add a new task to the list and tell it to use the `content` key to show in the UI
# and to use the key `done` to sync the task status with a checkbox element in the UI
myList.add(task)
# add a new task to the list and tell it to use the `content` key to show in the UI
# and to use the key `done` to sync the task status with a checkbox element in the UI
myList.add(task)
# clear the inputbox element used to create the new task
new_task_content.clear()
# clear the inputbox element used to create the new task
new_task_content.clear()
def on_click(evt):
add_task()
def on_click(evt):
add_task()
def handle_keypress(evt):
if evt.key == "Enter":
add_task()
def handle_keypress(evt):
if evt.key == "Enter":
add_task()
add_event_listener(
document.getElementById("new-task-content"),
"keypress",
handle_keypress
)
</py-script>
<div class="py-box">
<input id="new-task-content" />
<button py-click="add_task()" id="new-task-btn" class="py-button">
Add Task!
</button>
</div>
add_event_listener(
document.getElementById("new-task-content"),
"keypress",
handle_keypress
)
</py-script>
<div class="py-box">
<input id="new-task-content" />
<button
py-click="add_task()"
id="new-task-btn"
class="py-button"
>
Add Task!
</button>
</div>
<py-list id="myList"></py-list>
<py-repl id="my-repl" auto-generate="true"> </py-repl>
</py-tutor>
</section>
</body>
<py-list id="myList"></py-list>
<py-repl id="my-repl" auto-generate="true"> </py-repl>
</py-tutor>
</section>
</body>
</html>

View File

@@ -1,76 +1,83 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Todo App</title>
<title>Todo App</title>
<link rel="icon" type="image/png" href="favicon.png" />
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<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>
<link rel="stylesheet" href="./assets/css/examples.css" />
</head>
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
</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">Todo App</a>
</div>
</nav>
<section class="pyscript">
<py-tutor modules="./utils.py;./todo.py">
<py-config>
plugins = [
"../build/plugins/python/py_tutor.py"
]
[[fetch]]
files = ["./utils.py", "./todo.py"]
</py-config>
<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">Todo App</a>
</div>
</nav>
<section class="pyscript">
<py-tutor modules="./utils.py;./todo.py">
<py-config>
plugins = [
"../build/plugins/python/py_tutor.py"
]
[[fetch]]
files = ["./utils.py", "./todo.py"]
</py-config>
<py-script src="./todo.py"></py-script>
</py-tutor>
<main>
<section>
<div class="text-center w-full mb-8">
<h1
class="text-3xl font-bold text-gray-800 uppercase tracking-tight"
>
To Do List
</h1>
</div>
<div>
<input id="new-task-content" class="py-input" type="text" />
<button
id="new-task-btn"
class="py-button"
type="submit"
py-click="add_task()"
>
Add task
</button>
</div>
<py-script src="./todo.py"></py-script>
</py-tutor>
<main>
<section>
<div class="text-center w-full mb-8">
<h1
class="text-3xl font-bold text-gray-800 uppercase tracking-tight"
>
To Do List
</h1>
</div>
<div>
<input
id="new-task-content"
class="py-input"
type="text"
/>
<button
id="new-task-btn"
class="py-button"
type="submit"
py-click="add_task()"
>
Add task
</button>
</div>
<py-list id="myList"></py-list>
<div
id="list-tasks-container"
class="flex flex-col-reverse mt-4"
></div>
<py-list id="myList"></py-list>
<div
id="list-tasks-container"
class="flex flex-col-reverse mt-4"
></div>
<template id="task-template">
<section class="task py-li-element">
<label for="flex items-center p-2 ">
<input class="mr-2" type="checkbox" />
<p class="m-0 inline"></p>
</label>
</section>
</template>
<template id="task-template">
<section class="task py-li-element">
<label for="flex items-center p-2 ">
<input class="mr-2" type="checkbox" />
<p class="m-0 inline"></p>
</label>
</section>
</template>
</section>
</main>
</section>
</main>
</section>
</body>
</body>
</html>

View File

@@ -9,13 +9,13 @@ It can be served as a Single Page App from a static web server.
1. Create and activate a virtual environment, and move into the `freedom`
project directory:
$ python -m venv venv
$ . ./venv/bin/activate
$ cd freedom
$ python -m venv venv
$ . ./venv/bin/activate
$ cd freedom
2. Install Briefcase:
$ pip install briefcase
$ pip install briefcase
## Web app

View File

@@ -1,59 +1,62 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<title>Freedom Units</title>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<title>Freedom Units</title>
<link rel="icon" type="image/png" href="/static/logo-32.png" />
<link rel="icon" type="image/png" href="/static/logo-32.png" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link
rel="stylesheet"
href="https://pyscript.net/latest/pyscript.css"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"
integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N"
crossorigin="anonymous"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"
integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N"
crossorigin="anonymous"
/>
<link rel="stylesheet" href="/static/css/briefcase.css" />
</head>
<body>
<div id="app-placeholder"></div>
<link rel="stylesheet" href="/static/css/briefcase.css" />
</head>
<body>
<div id="app-placeholder"></div>
<script
src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
crossorigin="anonymous"
></script>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct"
crossorigin="anonymous"
></script>
<script
src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
crossorigin="anonymous"
></script>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct"
crossorigin="anonymous"
></script>
<py-config>
name = "Freedom Units"
description = "A testing app"
version = "0.0.1"
terminal = false
packages = [
"./static/wheels/freedom-0.0.1-py3-none-any.whl",
"toga_core==0.3.0",
"toga_web==0.3.0",
"travertino==0.1.3",
]
<py-config>
name = "Freedom Units"
description = "A testing app"
version = "0.0.1"
terminal = false
packages = [
"./static/wheels/freedom-0.0.1-py3-none-any.whl",
"toga_core==0.3.0",
"toga_web==0.3.0",
"travertino==0.1.3",
]
[splashscreen]
autoclose = true
</py-config>
<py-script>
import runpy
result = runpy.run_module("freedom", run_name="__main__", alter_sys=True)
</py-script>
</body>
[splashscreen]
autoclose = true
</py-config>
<py-script>
import runpy
result = runpy.run_module("freedom", run_name="__main__", alter_sys=True)
</py-script>
</body>
</html>

View File

@@ -1,13 +1,13 @@
/* Unset the overly generic pyscript .label style */
#app-placeholder .label {
margin-top: inherit;
color: inherit;
text-align: inherit;
width: inherit;
display: inherit;
color: inherit;
font-size: inherit;
margin-top: inherit;
margin-top: inherit;
color: inherit;
text-align: inherit;
width: inherit;
display: inherit;
color: inherit;
font-size: inherit;
margin-top: inherit;
}
/*******************************************************************
@@ -21,15 +21,15 @@
*******************************************************/
main.toga.window {
margin-top: 5em;
display: flex;
flex-direction: column;
margin-top: 5em;
display: flex;
flex-direction: column;
}
div.toga.box {
display: flex;
display: flex;
}
span.toga.label {
white-space: nowrap;
white-space: nowrap;
}

View File

@@ -1,192 +1,195 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Raycaster</title>
<link rel="icon" type="image/png" href="../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<div class="container-fluid fixed-top header disable-selection">
<div class="row">
<div class="col"></div>
<div class="col-md-6">
<div class="row">
<div class="col"></div>
</div>
<head>
<meta charset="UTF-8" />
<title>Raycaster</title>
<link rel="icon" type="image/png" href="../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<div class="container-fluid fixed-top header disable-selection">
<div class="row">
<div class="col"></div>
<div class="col-md-6">
<div class="row">
<div class="col"></div>
</div>
</div>
<div class="col"></div>
</div>
</div>
<div class="col"></div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.147.0/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.147.0/three.min.js"></script>
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<py-script>
from pyodide.ffi import create_proxy, to_js
from js import window
from js import Math
from js import THREE
from js import performance
from js import Object
from js import document
import asyncio
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link
rel="stylesheet"
href="https://pyscript.net/latest/pyscript.css"
/>
<py-script>
from pyodide.ffi import create_proxy, to_js
from js import window
from js import Math
from js import THREE
from js import performance
from js import Object
from js import document
import asyncio
mouse = THREE.Vector2.new();
mouse = THREE.Vector2.new();
renderer = THREE.WebGLRenderer.new({"antialias":True})
renderer.setSize(1000, 1000)
renderer.shadowMap.enabled = False
renderer.shadowMap.type = THREE.PCFSoftShadowMap
renderer.shadowMap.needsUpdate = True
renderer = THREE.WebGLRenderer.new({"antialias":True})
renderer.setSize(1000, 1000)
renderer.shadowMap.enabled = False
renderer.shadowMap.type = THREE.PCFSoftShadowMap
renderer.shadowMap.needsUpdate = True
document.body.appendChild( renderer.domElement )
document.body.appendChild( renderer.domElement )
import js, pyodide
def onMouseMove(event):
event.preventDefault();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
js.document.addEventListener('mousemove', pyodide.ffi.create_proxy(onMouseMove))
import js, pyodide
def onMouseMove(event):
event.preventDefault();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
js.document.addEventListener('mousemove', pyodide.ffi.create_proxy(onMouseMove))
camera = THREE.PerspectiveCamera.new( 35, window.innerWidth / window.innerHeight, 1, 500 )
scene = THREE.Scene.new()
cameraRange = 3
camera = THREE.PerspectiveCamera.new( 35, window.innerWidth / window.innerHeight, 1, 500 )
scene = THREE.Scene.new()
cameraRange = 3
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize( window.innerWidth, window.innerHeight )
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize( window.innerWidth, window.innerHeight )
setcolor = "#000000"
setcolor = "#000000"
scene.background = THREE.Color.new(setcolor)
scene.fog = THREE.Fog.new(setcolor, 2.5, 3.5);
scene.background = THREE.Color.new(setcolor)
scene.fog = THREE.Fog.new(setcolor, 2.5, 3.5);
sceneGroup = THREE.Object3D.new();
particularGroup = THREE.Object3D.new();
sceneGroup = THREE.Object3D.new();
particularGroup = THREE.Object3D.new();
def mathRandom(num = 1):
setNumber = - Math.random() * num + Math.random() * num
return setNumber
def mathRandom(num = 1):
setNumber = - Math.random() * num + Math.random() * num
return setNumber
particularGroup = THREE.Object3D.new();
modularGroup = THREE.Object3D.new();
particularGroup = THREE.Object3D.new();
modularGroup = THREE.Object3D.new();
perms = {"flatShading":True, "color":"#111111", "transparent":False, "opacity":1, "wireframe":False}
perms = Object.fromEntries(to_js(perms))
perms = {"flatShading":True, "color":"#111111", "transparent":False, "opacity":1, "wireframe":False}
perms = Object.fromEntries(to_js(perms))
particle_perms = {"color":"#FFFFFF", "side":THREE.DoubleSide}
particle_perms = Object.fromEntries(to_js(particle_perms))
particle_perms = {"color":"#FFFFFF", "side":THREE.DoubleSide}
particle_perms = Object.fromEntries(to_js(particle_perms))
def create_cubes(mathRandom, modularGroup):
i = 0
while i < 30:
geometry = THREE.IcosahedronGeometry.new();
material = THREE.MeshStandardMaterial.new(perms);
cube = THREE.Mesh.new(geometry, material);
cube.speedRotation = Math.random() * 0.1;
cube.positionX = mathRandom();
cube.positionY = mathRandom();
cube.positionZ = mathRandom();
cube.castShadow = True;
cube.receiveShadow = True;
newScaleValue = mathRandom(0.3);
cube.scale.set(newScaleValue,newScaleValue,newScaleValue);
cube.rotation.x = mathRandom(180 * Math.PI / 180);
cube.rotation.y = mathRandom(180 * Math.PI / 180);
cube.rotation.z = mathRandom(180 * Math.PI / 180);
cube.position.set(cube.positionX, cube.positionY, cube.positionZ);
modularGroup.add(cube);
i += 1
def create_cubes(mathRandom, modularGroup):
i = 0
while i < 30:
geometry = THREE.IcosahedronGeometry.new();
material = THREE.MeshStandardMaterial.new(perms);
cube = THREE.Mesh.new(geometry, material);
cube.speedRotation = Math.random() * 0.1;
cube.positionX = mathRandom();
cube.positionY = mathRandom();
cube.positionZ = mathRandom();
cube.castShadow = True;
cube.receiveShadow = True;
newScaleValue = mathRandom(0.3);
cube.scale.set(newScaleValue,newScaleValue,newScaleValue);
cube.rotation.x = mathRandom(180 * Math.PI / 180);
cube.rotation.y = mathRandom(180 * Math.PI / 180);
cube.rotation.z = mathRandom(180 * Math.PI / 180);
cube.position.set(cube.positionX, cube.positionY, cube.positionZ);
modularGroup.add(cube);
i += 1
create_cubes(mathRandom, modularGroup)
create_cubes(mathRandom, modularGroup)
def generateParticle(mathRandom, particularGroup, num, amp = 2):
gmaterial = THREE.MeshPhysicalMaterial.new(particle_perms);
gparticular = THREE.CircleGeometry.new(0.2,5);
i = 0
while i < num:
pscale = 0.001+Math.abs(mathRandom(0.03));
particular = THREE.Mesh.new(gparticular, gmaterial);
particular.position.set(mathRandom(amp),mathRandom(amp),mathRandom(amp));
particular.rotation.set(mathRandom(),mathRandom(),mathRandom());
particular.scale.set(pscale,pscale,pscale);
particular.speedValue = mathRandom(1);
particularGroup.add(particular);
i += 1
def generateParticle(mathRandom, particularGroup, num, amp = 2):
gmaterial = THREE.MeshPhysicalMaterial.new(particle_perms);
gparticular = THREE.CircleGeometry.new(0.2,5);
i = 0
while i < num:
pscale = 0.001+Math.abs(mathRandom(0.03));
particular = THREE.Mesh.new(gparticular, gmaterial);
particular.position.set(mathRandom(amp),mathRandom(amp),mathRandom(amp));
particular.rotation.set(mathRandom(),mathRandom(),mathRandom());
particular.scale.set(pscale,pscale,pscale);
particular.speedValue = mathRandom(1);
particularGroup.add(particular);
i += 1
generateParticle(mathRandom, particularGroup, 200, 2)
generateParticle(mathRandom, particularGroup, 200, 2)
sceneGroup.add(particularGroup);
scene.add(modularGroup);
scene.add(sceneGroup);
sceneGroup.add(particularGroup);
scene.add(modularGroup);
scene.add(sceneGroup);
camera.position.set(0, 0, cameraRange);
cameraValue = False;
camera.position.set(0, 0, cameraRange);
cameraValue = False;
ambientLight = THREE.AmbientLight.new(0xFFFFFF, 0.1);
ambientLight = THREE.AmbientLight.new(0xFFFFFF, 0.1);
light = THREE.SpotLight.new(0xFFFFFF, 3);
light.position.set(5, 5, 2);
light.castShadow = True;
light.shadow.mapSize.width = 10000;
light.shadow.mapSize.height = light.shadow.mapSize.width;
light.penumbra = 0.5;
light = THREE.SpotLight.new(0xFFFFFF, 3);
light.position.set(5, 5, 2);
light.castShadow = True;
light.shadow.mapSize.width = 10000;
light.shadow.mapSize.height = light.shadow.mapSize.width;
light.penumbra = 0.5;
lightBack = THREE.PointLight.new(0x0FFFFF, 1);
lightBack.position.set(0, -3, -1);
lightBack = THREE.PointLight.new(0x0FFFFF, 1);
lightBack.position.set(0, -3, -1);
scene.add(sceneGroup);
scene.add(light);
scene.add(lightBack);
scene.add(sceneGroup);
scene.add(light);
scene.add(lightBack);
rectSize = 2
intensity = 14
rectLight = THREE.RectAreaLight.new( 0x0FFFFF, intensity, rectSize, rectSize )
rectLight.position.set( 0, 0, 1 )
rectLight.lookAt( 0, 0, 0 )
scene.add( rectLight )
rectSize = 2
intensity = 14
rectLight = THREE.RectAreaLight.new( 0x0FFFFF, intensity, rectSize, rectSize )
rectLight.position.set( 0, 0, 1 )
rectLight.lookAt( 0, 0, 0 )
scene.add( rectLight )
raycaster = THREE.Raycaster.new();
uSpeed = 0.1
raycaster = THREE.Raycaster.new();
uSpeed = 0.1
time = 0.0003;
camera.lookAt(scene.position)
time = 0.0003;
camera.lookAt(scene.position)
async def main():
while True:
time = performance.now() * 0.0003;
i = 0
while i < particularGroup.children.length:
newObject = particularGroup.children[i];
newObject.rotation.x += newObject.speedValue/10;
newObject.rotation.y += newObject.speedValue/10;
newObject.rotation.z += newObject.speedValue/10;
i += 1
async def main():
while True:
time = performance.now() * 0.0003;
i = 0
while i < particularGroup.children.length:
newObject = particularGroup.children[i];
newObject.rotation.x += newObject.speedValue/10;
newObject.rotation.y += newObject.speedValue/10;
newObject.rotation.z += newObject.speedValue/10;
i += 1
i = 0
while i < modularGroup.children.length:
newCubes = modularGroup.children[i];
newCubes.rotation.x += 0.008;
newCubes.rotation.y += 0.005;
newCubes.rotation.z += 0.003;
i = 0
while i < modularGroup.children.length:
newCubes = modularGroup.children[i];
newCubes.rotation.x += 0.008;
newCubes.rotation.y += 0.005;
newCubes.rotation.z += 0.003;
newCubes.position.x = Math.sin(time * newCubes.positionZ) * newCubes.positionY;
newCubes.position.y = Math.cos(time * newCubes.positionX) * newCubes.positionZ;
newCubes.position.z = Math.sin(time * newCubes.positionY) * newCubes.positionX;
i += 1
newCubes.position.x = Math.sin(time * newCubes.positionZ) * newCubes.positionY;
newCubes.position.y = Math.cos(time * newCubes.positionX) * newCubes.positionZ;
newCubes.position.z = Math.sin(time * newCubes.positionY) * newCubes.positionX;
i += 1
particularGroup.rotation.y += 0.005;
particularGroup.rotation.y += 0.005;
modularGroup.rotation.y -= ((mouse.x * 4) + modularGroup.rotation.y) * uSpeed;
modularGroup.rotation.x -= ((-mouse.y * 4) + modularGroup.rotation.x) * uSpeed;
modularGroup.rotation.y -= ((mouse.x * 4) + modularGroup.rotation.y) * uSpeed;
modularGroup.rotation.x -= ((-mouse.y * 4) + modularGroup.rotation.x) * uSpeed;
renderer.render( scene, camera )
await asyncio.sleep(0.02)
renderer.render( scene, camera )
await asyncio.sleep(0.02)
asyncio.ensure_future(main())
</py-script>
</body>
asyncio.ensure_future(main())
</py-script>
</body>
</html>

View File

@@ -1,55 +1,55 @@
body {
margin: 0;
text-align: center;
background-color: black;
cursor: crosshair;
margin: 0;
text-align: center;
background-color: black;
cursor: crosshair;
}
canvas {
display: block;
width: 100%;
height: 100%;
display: block;
width: 100%;
height: 100%;
}
.header {
/*top:45%;*/
top: 45%;
color: #dddddd;
/*top:45%;*/
top: 45%;
color: #dddddd;
}
.footer {
bottom: 3%;
bottom: 3%;
}
.description {
color: gray;
padding-top: 50px;
color: gray;
padding-top: 50px;
}
.btn {
border-radius: 30px;
padding: 10px 30px;
border-radius: 30px;
padding: 10px 30px;
}
a,
a:hover,
a:visited {
color: red;
text-decoration: none;
color: red;
text-decoration: none;
}
.disable-selection {
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer */
-khtml-user-select: none; /* KHTML browsers (e.g. Konqueror) */
-webkit-user-select: none; /* Chrome, Safari, and Opera */
-webkit-touch-callout: none; /* Disable Android and iOS callouts*/
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer */
-khtml-user-select: none; /* KHTML browsers (e.g. Konqueror) */
-webkit-user-select: none; /* Chrome, Safari, and Opera */
-webkit-touch-callout: none; /* Disable Android and iOS callouts*/
}
h1::after {
content: " V 2.0";
font-size: 12px;
position: absolute;
top: 3px;
padding-left: 5px;
font-weight: 400;
content: " V 2.0";
font-size: 12px;
position: absolute;
top: 3px;
padding-left: 5px;
font-weight: 400;
}
h2::after {
content: "2";
font-size: 12px;
position: absolute;
top: 14px;
padding-left: 5px;
content: "2";
font-size: 12px;
position: absolute;
top: 14px;
padding-left: 5px;
}