Compare commits

..

1 Commits

Author SHA1 Message Date
dylan
3390e9d50a initial ideas 2023-04-28 17:57:35 -07:00
42 changed files with 1363 additions and 4604 deletions

1
.gitignore vendored
View File

@ -1 +0,0 @@
build

View File

@ -1,4 +0,0 @@
{
"deno.enable": true,
"deno.unstable": true
}

View File

@ -1,25 +1,2 @@
# Faux
# fantasy-console
This is a custom fantasy-console (like Pico 8) written in Deno/Typescript.
Go to the [Releases](https://git.playbox.link/dylan/fantasy-console/releases) page to find downloadable executables.
NOTE: If you are running Faux on Linux, you will need to have `xsel` installed.
## Developing
Faux is written in [TypeScript](https://www.typescriptlang.org/) to be run or compiled by [Deno](https://deno.com/runtime).
If you want to build from source, you should have Deno installed, clone this repo, and then...
To run:
```
deno task run
```
To compile:
```
deno task build_all
```
NOTE: Development is happening solely on Linux, so some build commands may fail if you are not on Linux or do not have some build dependencies installed.

View File

@ -1 +0,0 @@
[{"sheet_type":"code","value":""},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null}]

File diff suppressed because one or more lines are too long

View File

@ -1,707 +0,0 @@
[
{
"sheet_type": "code",
"value": "x = code(1);\nreturn {\n\tinit: () => {y = 0},\n\tupdate: () => {\n\t\ty += speed;\n\t\tif (y > 127) {\n\t\t\ty = -6\n\t\t}\n\t},\n\tdraw: () => {\n\t\tcls();\n\t\ttxt(x, y, 'hello world')\n\t}\n}"
},
{
"sheet_type": "code",
"value": "sprsht(15);\nspeed = 2;\nreturn 8;"
},
{
"sheet_type": "none",
"value": null
},
{
"sheet_type": "none",
"value": null
},
{
"sheet_type": "none",
"value": null
},
{
"sheet_type": "none",
"value": null
},
{
"sheet_type": "none",
"value": null
},
{
"sheet_type": "none",
"value": null
},
{
"sheet_type": "none",
"value": null
},
{
"sheet_type": "none",
"value": null
},
{
"sheet_type": "none",
"value": null
},
{
"sheet_type": "none",
"value": null
},
{
"sheet_type": "none",
"value": null
},
{
"sheet_type": "none",
"value": null
},
{
"sheet_type": "none",
"value": null
},
{
"sheet_type": "spritesheet",
"value": [
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 2, 0, 0, 2, 0, 0,
0, 0, 0, 2, 2, 0, 0, 0,
0, 0, 0, 2, 2, 0, 0, 0,
0, 0, 2, 0, 0, 2, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
1, 1, 1, 1, 1, 1, 1, 1,
1, 3, 3, 1, 1, 3, 3, 1,
1, 3, 3, 1, 1, 3, 3, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 3, 3, 1, 1, 3, 3, 1,
1, 3, 3, 1, 1, 3, 3, 1,
1, 1, 1, 1, 1, 1, 1, 1
],
[
6, 6, 6, 4, 4, 4, 5, 5,
6, 6, 4, 4, 4, 5, 5, 5,
6, 4, 4, 4, 5, 5, 5, 6,
4, 4, 4, 5, 5, 5, 6, 6,
4, 4, 5, 5, 5, 6, 6, 6,
4, 5, 5, 5, 6, 6, 6, 4,
5, 5, 5, 6, 6, 6, 4, 4,
5, 5, 6, 6, 6, 4, 4, 4
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
]
]
}
]

158
colors.html Normal file
View File

@ -0,0 +1,158 @@
<html>
<head>
<title></title>
<style>
.swatch {
width: 100px;
height: 100px;
background-color: hsl(var(--hue), var(--saturation), var(--lightness));
}
.h1p {
--hue: 310;
}
.h1 {
--hue: 340;
}
.h1s {
--hue: 335;
}
.h2d {
--hue: 50;
}
.h2 {
--hue: 37;
}
.h2s {
--hue: 30;
}
.h2h {
--hue: 57;
}
.h3 {
--hue: 130;
}
.h3s {
--hue: 145;
}
.h3h {
--hue: 203;
}
.h4 {
--hue: 224;
}
/* .h4hs {
--hue: 228;
}
.h4s {
--hue: 235;
} */
.h4hs {
--hue: 235;
}
.h4s {
--hue: 240;
}
.h5 {
--hue: 250;
}
.h6 {
--hue: 230;
}
.h7 {
--hue: 30;
}
.sp {
--saturation: 90%;
}
.s1 {
--saturation: 85%;
}
.s1x {
--saturation: 75%;
}
.sx {
--saturation: 65%;
}
.smx {
--saturation: 60%;
}
.sm {
--saturation: 55%;
}
.smm {
--saturation: 50%;
}
.s2 {
--saturation: 45%;
}
.ss {
--saturation: 40%;
}
.sl {
--saturation: 25%;
}
.s3 {
--saturation: 13%;
}
.l0 {
--lightness: 95%;
}
.l1 {
--lightness: 82%;
}
.l1h {
--lightness: 75%;
}
.l1hh {
--lightness: 70%;
}
.l2 {
--lightness: 67%;
}
.l2m {
--lightness: 62%;
}
.lm {
--lightness: 58%;
}
.l3 {
--lightness: 50%;
}
.l3h {
--lightness: 40%;
}
.l4 {
--lightness: 30%;
}
.l4h {
--lightness: 25%;
}
.l5 {
--lightness: 20%;
}
.l6 {
--lightness: 5%;
}
.row {
display: flex;
}
#palette {
display: flex;
flex-wrap: wrap;
}
</style>
</head>
<body>
<div id="palette"></div>
<script src="colors.js"></script>
<script>
const div = document.getElementById("palette");
div.innerHTML = palette.map(c => `<div class="swatch" style="background-color: hsl(${c[0]}, ${c[1]}%, ${c[2]}%);"></div>`).join("");
</script>
</body>
</html>

54
colors.js Normal file
View File

@ -0,0 +1,54 @@
const hue_gray = 230;
const hue_brown = 30;
const hue_orange = 37;
const hue_purple = 250;
const hue_pink = 310;
const hue_red = 340;
const hue_red_shade = 335;
const hue_yellow = 57;
const hue_green = 130;
const hue_green_shade = 145;
const hue_sky = 203;
const hue_blue = 224;
const hue_blue_shade = 235;
const hue_blue_shade_2 = 240;
const saturation_max = 90;
const saturation_normal = 60;
const saturation_low = 40;
const saturation_min = 13;
const lightness_max = 95;
const lightness_light = 67;
const lightness_mediumlight = 62;
const lightness_medium = 50;
const lightness_mediumdark = 40;
const lightness_dark = 30;
const lightness_almostverydark = 25;
const lightness_verydark = 20;
const lightness_min = 5;
const hsl = (h, s, l) => [h, s, l];
const palette = [
hsl(hue_gray, saturation_min, lightness_max),
hsl(hue_gray, saturation_min, lightness_light),
hsl(hue_gray, saturation_min, lightness_dark),
hsl(hue_gray, saturation_min, lightness_min),
hsl(hue_orange, saturation_normal, lightness_medium),
hsl(hue_brown, saturation_low, lightness_light),
hsl(hue_brown, saturation_low, lightness_mediumdark),
hsl(hue_brown, saturation_low, lightness_almostverydark),
hsl(hue_purple, saturation_normal, lightness_light),
hsl(hue_pink, saturation_normal, lightness_light),
hsl(hue_red, saturation_normal, lightness_medium),
hsl(hue_red_shade, saturation_normal, lightness_dark),
hsl(hue_yellow, saturation_max, lightness_mediumlight),
hsl(hue_green, saturation_normal, lightness_medium),
hsl(hue_green_shade, saturation_normal, lightness_dark),
hsl(hue_green_shade, saturation_normal, lightness_verydark),
hsl(hue_sky, saturation_max, lightness_light),
hsl(hue_blue, saturation_normal, lightness_medium),
hsl(hue_blue_shade, saturation_normal, lightness_mediumdark),
hsl(hue_blue_shade_2, saturation_normal, lightness_dark),
]

54
colors2.js Normal file
View File

@ -0,0 +1,54 @@
const hue_gray = 230;
const hue_brown = 25;
const hue_brown_shade = 10;
const hue_orange = 37;
const hue_purple = 250;
const hue_pink = 310;
const hue_red = 340;
const hue_red_shade = 335;
const hue_redbrown_dark = 0;
const hue_yellow = 57;
const hue_green = 140;
const hue_green_shade = 145;
const hue_sky = 203;
const hue_blue = 240;
const hue_blue_shade = 235;
const hue_blue_shade_2 = 240;
const hue_bluegreen_dark = 215;
const saturation_max = 90;
const saturation_normal = 60;
const saturation_low = 40;
const saturation_min = 13;
const lightness_max = 95;
const lightness_light = 67;
const lightness_mediumlight = 62;
const lightness_medium = 50;
const lightness_mediumdark = 40;
const lightness_dark = 30;
const lightness_almostverydark = 25;
const lightness_verydark = 20;
const lightness_min = 5;
const hsl = (h, s, l) => [h, s, l];
const palette = [
hsl(hue_gray, saturation_min, lightness_max),
hsl(hue_gray, saturation_min, lightness_light),
hsl(hue_gray, saturation_min, lightness_dark),
hsl(hue_gray, saturation_min, lightness_min),
hsl(hue_orange, saturation_normal, lightness_medium),
hsl(hue_brown, saturation_low, lightness_light),
hsl(hue_brown_shade, saturation_low, lightness_mediumdark),
hsl(hue_pink, saturation_normal, lightness_light),
hsl(hue_red, saturation_normal, lightness_medium),
hsl(hue_red_shade, saturation_normal, lightness_dark),
hsl(hue_yellow, saturation_max, lightness_mediumlight),
hsl(hue_green, saturation_normal, lightness_medium),
hsl(hue_green_shade, saturation_normal, lightness_dark),
hsl(hue_sky, saturation_max, lightness_light),
hsl(hue_blue, saturation_normal, lightness_mediumlight),
hsl(hue_blue_shade, saturation_normal, lightness_mediumdark),
hsl(hue_bluegreen_dark, saturation_normal, lightness_verydark),
]

View File

@ -1,119 +0,0 @@
const hue_gray = 230;
const hue_brown = 30;
const hue_orange = 37;
const hue_purple = 280;
const hue_pink = 310;
const hue_red = 340;
const hue_red_shade = 335;
const hue_yellow = 57;
const hue_green = 130;
const hue_green_shade = 145;
const hue_sky = 203;
const hue_blue = 224;
const hue_blue_shade = 235;
const hue_blue_shade_2 = 240;
const saturation_max = 90;
const saturation_normal = 60;
const saturation_low = 40;
const saturation_min = 13;
const lightness_max = 95;
const lightness_light = 67;
const lightness_mediumlight = 62;
const lightness_medium = 50;
const lightness_mediumdark = 40;
const lightness_dark = 30;
const lightness_almostverydark = 25;
const lightness_verydark = 20;
const lightness_min = 5;
/**
* Converts an HSL color value to RGB. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* Assumes h, s, and l are contained in the set [0, 1] and
* returns r, g, and b in the set [0, 255].
*
* @param Number h The hue
* @param Number s The saturation
* @param Number l The lightness
* @return Array The RGB representation
*/
function hsl(h: number, s: number, l: number): [number, number, number] {
h = h / 360;
s = s/100;
l = l/100;
let r, g, b;
if (s == 0) {
r = g = b = l; // achromatic
} else {
const hue2rgb = (p: number, q: number, t: number) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return [ r , g , b ];
}
const colors = {
TRANSPARENT: [0, 0, 0],
BLACK2: [0, 0, 0],
BLACK3: [0, 0, 0],
BLACK4: [0, 0, 0],
WHITE: hsl(hue_gray, saturation_min, lightness_max),
LIGHTGRAY: hsl(hue_gray, saturation_min, lightness_light),
DARKGRAY: hsl(hue_gray, saturation_min, lightness_dark),
BLACK: hsl(hue_gray, saturation_min, lightness_min),
ORANGE: hsl(hue_orange, saturation_normal, lightness_medium),
TAN: hsl(hue_brown, saturation_low, lightness_light),
BROWN: hsl(hue_brown, saturation_low, lightness_mediumdark),
DARKBROWN: hsl(hue_brown, saturation_low, lightness_almostverydark),
PURPLE: hsl(hue_purple, saturation_normal, lightness_medium),
PINK: hsl(hue_pink, saturation_normal, lightness_light),
RED: hsl(hue_red, saturation_normal, lightness_medium),
DARKRED: hsl(hue_red_shade, saturation_normal, lightness_dark),
YELLOW: hsl(hue_yellow, saturation_max, lightness_mediumlight),
GREEN: hsl(hue_green, saturation_normal, lightness_medium),
DARKGREEN: hsl(hue_green_shade, saturation_normal, lightness_dark),
DARKERGREEN: hsl(hue_green_shade, saturation_normal, lightness_verydark),
CYAN: hsl(hue_sky, saturation_max, lightness_light),
BLUE: hsl(hue_blue, saturation_normal, lightness_medium),
DARKBLUE: hsl(hue_blue_shade, saturation_normal, lightness_mediumdark),
DARKERBLUE: hsl(hue_blue_shade_2, saturation_normal, lightness_dark),
} as const;
// const colors = {
// TRANSPARENT: [0, 0, 0],
// BLACK: [0, 0, 0],
// WHITE: [1, 1, 1],
// RED: [1, 0, 0],
// YELLOW: [1, 1, 0],
// GREEN: [0, 1, 0],
// BLUE: [0.1, 0.5, 1],
// DARKBLUE: [0.05, 0.1, 0.3],
// BROWN: [0.6, 0.5, 0.4],
// GRAY: [0.5, 0.5, 0.5],
// PURPLE: [0.7, 0.1, 0.85],
// ORANGE: [0.95, 0.75, 0.25],
// CYAN: [0, 0.9, 0.9],
// LIGHTGRAY: [0.75, 0.75, 0.75],
// REDDISH: [216/255, 59/255, 113/255],
// DARKGREEN: [0, 0.6, 0.2],
// } as const;
export const palette: Array<[number, number, number, number]> = Object.values(colors).map(val => [...val, 1]);
export const COLOR = Object.fromEntries(Object.keys(colors).map((name, i) => [name, Number(i)])) as {[key in keyof typeof colors]: number};

View File

@ -1,854 +0,0 @@
/**
* Perhaps fonts can be their own type of sheet. By the calculation below, we can fit ~4 fonts per fontsheet
*
* 3 bits for height
* 5 more metadata bits
* = 1 byte
*
* Per character:
* - 3 bits for width
* - 5 bits for metadata
* - 64 bits for pixels
* = 9 bytes per character
*
* 96 chars * 9 bytes =
*/
// export const fontWidth = 4;
// export const fontHeight = 6;
export const CHAR = {
UP: "À",
LEFT: "Á",
DOWN: "Â",
RIGHT: "Ã",
PI: "π"
}
export type Font = {
height: 6,
chars: {[key: string]: Array<number>},
};
// deno-fmt-ignore
export const font: Font = {
height: 6,
chars: {
"A": [
1, 1, 1,
1, 0, 1,
1, 1, 1,
1, 0, 1,
1, 0, 1,
0, 0, 0,
],
"B": [
1, 1, 1,
1, 0, 1,
1, 1, 0,
1, 0, 1,
1, 1, 1,
0, 0, 0,
],
"C": [
0, 1, 1,
1, 0, 0,
1, 0, 0,
1, 0, 0,
0, 1, 1,
0, 0, 0,
],
"D": [
1, 1, 0,
1, 0, 1,
1, 0, 1,
1, 0, 1,
1, 1, 0,
0, 0, 0,
],
"E": [
1, 1, 1,
1, 0, 0,
1, 1, 0,
1, 0, 0,
1, 1, 1,
0, 0, 0,
],
"F": [
1, 1, 1,
1, 0, 0,
1, 1, 0,
1, 0, 0,
1, 0, 0,
0, 0, 0,
],
"G": [
0, 1, 1,
1, 0, 0,
1, 0, 1,
1, 0, 1,
0, 1, 1,
0, 0, 0,
],
"H": [
1, 0, 1,
1, 0, 1,
1, 1, 1,
1, 0, 1,
1, 0, 1,
0, 0, 0,
],
"I": [
1, 1, 1,
0, 1, 0,
0, 1, 0,
0, 1, 0,
1, 1, 1,
0, 0, 0,
],
"J": [
1, 1, 1,
0, 1, 0,
0, 1, 0,
0, 1, 0,
1, 1, 0,
0, 0, 0,
],
"K": [
1, 0, 1,
1, 0, 1,
1, 1, 0,
1, 0, 1,
1, 0, 1,
0, 0, 0,
],
"L": [
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 1, 1,
0, 0, 0,
],
"M": [
1, 1, 1,
1, 1, 1,
1, 0, 1,
1, 0, 1,
1, 0, 1,
0, 0, 0,
],
"N": [
1, 1, 0,
1, 0, 1,
1, 0, 1,
1, 0, 1,
1, 0, 1,
0, 0, 0,
],
"O": [
0, 1, 1,
1, 0, 1,
1, 0, 1,
1, 0, 1,
1, 1, 0,
0, 0, 0,
],
"P": [
1, 1, 1,
1, 0, 1,
1, 1, 1,
1, 0, 0,
1, 0, 0,
0, 0, 0,
],
"Q": [
0, 1, 1,
1, 0, 1,
1, 0, 1,
1, 1, 0,
0, 1, 1,
0, 0, 0,
],
"R": [
1, 1, 1,
1, 0, 1,
1, 1, 0,
1, 0, 1,
1, 0, 1,
0, 0, 0,
],
"S": [
0, 1, 1,
1, 0, 0,
1, 1, 1,
0, 0, 1,
1, 1, 0,
0, 0, 0,
],
"T": [
1, 1, 1,
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 0, 0,
],
"U": [
1, 0, 1,
1, 0, 1,
1, 0, 1,
1, 0, 1,
0, 1, 1,
0, 0, 0,
],
"V": [
1, 0, 1,
1, 0, 1,
1, 0, 1,
1, 1, 1,
0, 1, 0,
0, 0, 0,
],
"W": [
1, 0, 1,
1, 0, 1,
1, 0, 1,
1, 1, 1,
1, 1, 1,
0, 0, 0,
],
"X": [
1, 0, 1,
1, 0, 1,
0, 1, 0,
1, 0, 1,
1, 0, 1,
0, 0, 0,
],
"Y": [
1, 0, 1,
1, 0, 1,
1, 1, 1,
0, 1, 0,
1, 0, 0,
0, 0, 0,
],
"Z": [
1, 1, 1,
0, 0, 1,
0, 1, 0,
1, 0, 0,
1, 1, 1,
0, 0, 0,
],
"a": [
0, 0, 0,
1, 1, 1,
0, 1, 1,
1, 0, 1,
1, 1, 1,
0, 0, 0,
],
"b": [
1, 0, 0,
1, 0, 0,
1, 1, 1,
1, 0, 1,
1, 1, 1,
0, 0, 0,
],
"c": [
0, 0, 0,
0, 0, 0,
1, 1, 1,
1, 0, 0,
1, 1, 1,
0, 0, 0,
],
"d": [
0, 0, 1,
0, 0, 1,
1, 1, 1,
1, 0, 1,
1, 1, 1,
0, 0, 0,
],
"e": [
0, 0, 0,
0, 1, 1,
1, 0, 1,
1, 1, 0,
0, 1, 1,
0, 0, 0,
],
"f": [
0, 1, 1,
1, 0, 0,
1, 1, 0,
1, 0, 0,
1, 0, 0,
0, 0, 0,
],
"g": [
0, 0, 0,
0, 0, 0,
1, 1, 1,
1, 0, 1,
0, 1, 1,
1, 1, 0,
],
"h": [
1, 0, 0,
1, 0, 0,
1, 1, 1,
1, 0, 1,
1, 0, 1,
0, 0, 0,
],
"i": [
0, 1, 0,
0, 0, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 0, 0,
],
"j": [
0, 1, 0,
0, 0, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
1, 0, 0,
],
"k": [
1, 0, 0,
1, 0, 0,
1, 0, 1,
1, 1, 0,
1, 0, 1,
0, 0, 0,
],
"l": [
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 0, 1,
0, 0, 0,
],
"m": [
0, 0, 0,
0, 0, 0,
1, 1, 1,
1, 1, 1,
1, 0, 1,
0, 0, 0,
],
"n": [
0, 0, 0,
0, 0, 0,
1, 1, 0,
1, 0, 1,
1, 0, 1,
0, 0, 0,
],
"o": [
0, 0, 0,
0, 0, 0,
0, 1, 1,
1, 0, 1,
1, 1, 0,
0, 0, 0,
],
"p": [
0, 0, 0,
0, 0, 0,
1, 1, 1,
1, 0, 1,
1, 1, 1,
1, 0, 0,
],
"q": [
0, 0, 0,
0, 0, 0,
1, 1, 1,
1, 0, 1,
1, 1, 1,
0, 0, 1,
],
"r": [
0, 0, 0,
0, 0, 0,
1, 1, 1,
1, 0, 0,
1, 0, 0,
0, 0, 0,
],
"s": [
0, 0, 0,
0, 0, 0,
0, 1, 1,
0, 1, 0,
1, 1, 0,
0, 0, 0,
],
"t": [
0, 1, 0,
0, 1, 0,
1, 1, 1,
0, 1, 0,
0, 1, 0,
0, 0, 0,
],
"u": [
0, 0, 0,
0, 0, 0,
1, 0, 1,
1, 0, 1,
0, 1, 1,
0, 0, 0,
],
"v": [
0, 0, 0,
0, 0, 0,
1, 0, 1,
1, 0, 1,
0, 1, 0,
0, 0, 0,
],
"w": [
0, 0, 0,
0, 0, 0,
1, 0, 1,
1, 1, 1,
1, 1, 1,
0, 0, 0,
],
"x": [
0, 0, 0,
0, 0, 0,
1, 0, 1,
0, 1, 0,
1, 0, 1,
0, 0, 0,
],
"y": [
0, 0, 0,
0, 0, 0,
1, 0, 1,
1, 0, 1,
0, 1, 0,
1, 0, 0,
],
"z": [
0, 0, 0,
0, 0, 0,
1, 1, 0,
0, 1, 0,
0, 1, 1,
0, 0, 0,
],
",": [
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 1, 0,
1, 0, 0,
],
".": [
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 1, 0,
0, 0, 0,
],
" ": [
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
],
"\t": [
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
],
"\n": [
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
],
"<": [
0, 0, 1,
0, 1, 0,
1, 0, 0,
0, 1, 0,
0, 0, 1,
0, 0, 0,
],
">": [
1, 0, 0,
0, 1, 0,
0, 0, 1,
0, 1, 0,
1, 0, 0,
0, 0, 0,
],
"=": [
0, 0, 0,
1, 1, 1,
0, 0, 0,
1, 1, 1,
0, 0, 0,
0, 0, 0,
],
"(": [
0, 0, 1,
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 0, 1,
0, 0, 0,
],
")": [
1, 0, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
1, 0, 0,
0, 0, 0,
],
"[": [
0, 1, 1,
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 1,
0, 0, 0,
],
"]": [
1, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
1, 1, 0,
0, 0, 0,
],
"{": [
0, 1, 1,
0, 1, 0,
1, 1, 0,
0, 1, 0,
0, 1, 1,
0, 0, 0,
],
"}": [
1, 1, 0,
0, 1, 0,
0, 1, 1,
0, 1, 0,
1, 1, 0,
0, 0, 0,
],
":": [
0, 0, 0,
0, 1, 0,
0, 0, 0,
0, 0, 0,
0, 1, 0,
0, 0, 0,
],
";": [
0, 0, 0,
0, 1, 0,
0, 0, 0,
0, 0, 0,
0, 1, 0,
1, 0, 0,
],
"'": [
0, 1, 0,
0, 1, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
],
'"': [
1, 0, 1,
1, 0, 1,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
],
"1": [
0, 1, 0,
1, 1, 0,
0, 1, 0,
0, 1, 0,
1, 1, 1,
0, 0, 0,
],
"2": [
0, 1, 0,
1, 0, 1,
0, 0, 1,
0, 1, 0,
1, 1, 1,
0, 0, 0,
],
"3": [
1, 1, 1,
0, 0, 1,
0, 1, 0,
0, 0, 1,
1, 1, 0,
0, 0, 0,
],
"4": [
1, 0, 1,
1, 0, 1,
1, 1, 1,
0, 0, 1,
0, 0, 1,
0, 0, 0,
],
"5": [
1, 1, 1,
1, 0, 0,
1, 1, 0,
0, 0, 1,
1, 1, 0,
0, 0, 0,
],
"6": [
0, 0, 1,
0, 1, 0,
1, 1, 1,
1, 0, 1,
1, 1, 1,
0, 0, 0,
],
"7": [
1, 1, 1,
0, 0, 1,
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 0, 0,
],
"8": [
1, 1, 1,
1, 0, 1,
1, 1, 1,
1, 0, 1,
1, 1, 1,
0, 0, 0,
],
"9": [
1, 1, 1,
1, 0, 1,
1, 1, 1,
0, 1, 0,
1, 0, 0,
0, 0, 0,
],
"0": [
1, 1, 1,
1, 0, 1,
1, 0, 1,
1, 0, 1,
1, 1, 1,
0, 0, 0,
],
"+": [
0, 0, 0,
0, 1, 0,
1, 1, 1,
0, 1, 0,
0, 0, 0,
0, 0, 0,
],
"-": [
0, 0, 0,
0, 0, 0,
1, 1, 1,
0, 0, 0,
0, 0, 0,
0, 0, 0,
],
"_": [
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
1, 1, 1,
0, 0, 0,
],
"`": [
1, 0, 0,
0, 1, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
],
"~": [
0, 0, 0,
0, 0, 1,
1, 1, 1,
1, 0, 0,
0, 0, 0,
0, 0, 0,
],
"/": [
0, 0, 1,
0, 0, 1,
0, 1, 0,
1, 0, 0,
1, 0, 0,
0, 0, 0,
],
"?": [
1, 1, 1,
0, 0, 1,
0, 1, 1,
0, 0, 0,
0, 1, 0,
0, 0, 0,
],
"\\": [
1, 0, 0,
1, 0, 0,
0, 1, 0,
0, 0, 1,
0, 0, 1,
0, 0, 0,
],
"|": [
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 0, 0,
],
"!": [
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 0, 0,
0, 1, 0,
0, 0, 0,
],
"@": [
0, 1, 0,
1, 0, 1,
1, 0, 1,
1, 0, 0,
0, 1, 1,
0, 0, 0,
],
"#": [
1, 0, 1,
1, 1, 1,
1, 0, 1,
1, 1, 1,
1, 0, 1,
0, 0, 0,
],
"$": [
1, 1, 1,
1, 1, 0,
0, 1, 1,
1, 1, 1,
0, 1, 0,
0, 0, 0,
],
"%": [
1, 0, 1,
0, 0, 1,
0, 1, 0,
1, 0, 0,
1, 0, 1,
0, 0, 0,
],
"^": [
0, 1, 0,
1, 0, 1,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
],
"&": [
1, 1, 0,
1, 1, 0,
0, 1, 1,
1, 0, 1,
1, 1, 1,
0, 0, 0,
],
"*": [
0, 1, 0,
1, 1, 1,
0, 1, 0,
1, 0, 1,
0, 0, 0,
0, 0, 0,
],
[CHAR.UP]: [
0, 1, 1, 1, 1, 1, 0,
1, 1, 1, 0, 1, 1, 1,
1, 1, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 1, 1,
0, 1, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0,
],
[CHAR.LEFT]: [
0, 1, 1, 1, 1, 1, 0,
1, 1, 1, 0, 0, 1, 1,
1, 1, 0, 0, 0, 1, 1,
1, 1, 1, 0, 0, 1, 1,
0, 1, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0,
],
[CHAR.DOWN]: [
0, 1, 1, 1, 1, 1, 0,
1, 1, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 1, 1,
1, 1, 1, 0, 1, 1, 1,
0, 1, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0,
],
[CHAR.RIGHT]: [
0, 1, 1, 1, 1, 1, 0,
1, 1, 0, 0, 1, 1, 1,
1, 1, 0, 0, 0, 1, 1,
1, 1, 0, 0, 1, 1, 1,
0, 1, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0,
],
[CHAR.PI]: [
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
1, 1, 1, 1, 1,
0, 1, 0, 1, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
],
}
};

View File

@ -1,54 +0,0 @@
export const codeIcon = [
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 1, 0, 0,
0, 1, 1, 0, 0, 1, 1, 0,
0, 1, 0, 0, 0, 0, 1, 0,
0, 1, 0, 0, 0, 0, 1, 0,
0, 1, 1, 0, 0, 1, 1, 0,
0, 0, 1, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
];
export const spriteIcon = [
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 1, 1, 1, 0, 0,
0, 1, 1, 0, 1, 1, 1, 0,
0, 1, 1, 1, 1, 0, 0, 0,
0, 1, 1, 1, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 0,
0, 0, 1, 1, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
];
export const mapIcon = [
0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 0,
0, 1, 0, 1, 0, 0, 1, 0,
0, 1, 0, 1, 1, 1, 1, 0,
0, 1, 1, 1, 0, 0, 1, 0,
0, 1, 0, 1, 0, 0, 1, 0,
0, 1, 1, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0,
];
export const sheetsIcon = [
0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 0, 0, 1, 1, 0,
0, 1, 1, 0, 0, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 0, 0, 1, 1, 0,
0, 1, 1, 0, 0, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0,
];
export const trashIcon = [
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 1, 1, 1, 0, 0,
0, 0, 1, 1, 1, 1, 0, 0,
0, 0, 1, 1, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
];

View File

@ -1 +0,0 @@
[{"sheet_type":"code","value":"// Sample\n\nreturn {\n\tinit() {},\n\tupdate() {},\n\tdraw() {\n\t\tcls();\n\t\ttxt(10,10,\"Hello, World!\");\n\t}\n}"},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null}]

View File

@ -1,12 +0,0 @@
{
"fmt": {
"useTabs": true
},
"tasks": {
"run": "deno run -A --unstable index.ts",
"build": "deno compile --output build/faux -A --unstable index.ts",
"build_linux": "mkdir -p ./build/zips ; mkdir -p ./build/linux ; cp ./manual.md ./build/linux/README.md ; deno compile --output build/linux/faux --target x86_64-unknown-linux-gnu -A --unstable index.ts ; cd ./build/linux ; zip -r ../zips/faux_linux.zip . ; cd ../..",
"build_windows": "mkdir -p ./build/zips ; mkdir -p ./build/windows ; cp ./manual.md ./build/windows/README.md ; deno compile --output build/windows/faux --target x86_64-pc-windows-msvc -A --unstable index.ts ; cd ./build/windows ; zip -r ../zips/faux_windows.zip . ; cd ../..",
"build_all": "deno task build_linux & deno task build_windows"
}
}

73
deno.lock generated
View File

@ -1,73 +0,0 @@
{
"version": "2",
"remote": {
"https://deno.land/std@0.186.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462",
"https://deno.land/std@0.186.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3",
"https://deno.land/std@0.186.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0",
"https://deno.land/std@0.186.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b",
"https://deno.land/std@0.186.0/path/_util.ts": "d7abb1e0dea065f427b89156e28cdeb32b045870acdf865833ba808a73b576d0",
"https://deno.land/std@0.186.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000",
"https://deno.land/std@0.186.0/path/glob.ts": "d479e0a695621c94d3fd7fe7abd4f9499caf32a8de13f25073451c6ef420a4e1",
"https://deno.land/std@0.186.0/path/mod.ts": "ee161baec5ded6510ee1d1fb6a75a0f5e4b41f3f3301c92c716ecbdf7dae910d",
"https://deno.land/std@0.186.0/path/posix.ts": "8b7c67ac338714b30c816079303d0285dd24af6b284f7ad63da5b27372a2c94d",
"https://deno.land/std@0.186.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1",
"https://deno.land/std@0.186.0/path/win32.ts": "d186344e5583bcbf8b18af416d13d82b35a317116e6460a5a3953508c3de5bba",
"https://deno.land/std@0.97.0/_util/assert.ts": "2f868145a042a11d5ad0a3c748dcf580add8a0dbc0e876eaa0026303a5488f58",
"https://deno.land/std@0.97.0/_util/os.ts": "e282950a0eaa96760c0cf11e7463e66babd15ec9157d4c9ed49cc0925686f6a7",
"https://deno.land/std@0.97.0/encoding/base64.ts": "eecae390f1f1d1cae6f6c6d732ede5276bf4b9cd29b1d281678c054dc5cc009e",
"https://deno.land/std@0.97.0/encoding/hex.ts": "f952e0727bddb3b2fd2e6889d104eacbd62e92091f540ebd6459317a61932d9b",
"https://deno.land/std@0.97.0/fs/_util.ts": "f2ce811350236ea8c28450ed822a5f42a0892316515b1cd61321dec13569c56b",
"https://deno.land/std@0.97.0/fs/ensure_dir.ts": "b7c103dc41a3d1dbbb522bf183c519c37065fdc234831a4a0f7d671b1ed5fea7",
"https://deno.land/std@0.97.0/fs/exists.ts": "b0d2e31654819cc2a8d37df45d6b14686c0cc1d802e9ff09e902a63e98b85a00",
"https://deno.land/std@0.97.0/hash/_wasm/hash.ts": "cb6ad1ab429f8ac9d6eae48f3286e08236d662e1a2e5cfd681ba1c0f17375895",
"https://deno.land/std@0.97.0/hash/_wasm/wasm.js": "94b1b997ae6fb4e6d2156bcea8f79cfcd1e512a91252b08800a92071e5e84e1a",
"https://deno.land/std@0.97.0/hash/hasher.ts": "57a9ec05dd48a9eceed319ac53463d9873490feea3832d58679df6eec51c176b",
"https://deno.land/std@0.97.0/hash/mod.ts": "5d032bd34186cda2f8d17fc122d621430953a6030d4b3f11172004715e3e2441",
"https://deno.land/std@0.97.0/path/_constants.ts": "1247fee4a79b70c89f23499691ef169b41b6ccf01887a0abd131009c5581b853",
"https://deno.land/std@0.97.0/path/_interface.ts": "1fa73b02aaa24867e481a48492b44f2598cd9dfa513c7b34001437007d3642e4",
"https://deno.land/std@0.97.0/path/_util.ts": "2e06a3b9e79beaf62687196bd4b60a4c391d862cfa007a20fc3a39f778ba073b",
"https://deno.land/std@0.97.0/path/common.ts": "eaf03d08b569e8a87e674e4e265e099f237472b6fd135b3cbeae5827035ea14a",
"https://deno.land/std@0.97.0/path/glob.ts": "314ad9ff263b895795208cdd4d5e35a44618ca3c6dd155e226fb15d065008652",
"https://deno.land/std@0.97.0/path/mod.ts": "4465dc494f271b02569edbb4a18d727063b5dbd6ed84283ff906260970a15d12",
"https://deno.land/std@0.97.0/path/posix.ts": "f56c3c99feb47f30a40ce9d252ef6f00296fa7c0fcb6dd81211bdb3b8b99ca3b",
"https://deno.land/std@0.97.0/path/separator.ts": "8fdcf289b1b76fd726a508f57d3370ca029ae6976fcde5044007f062e643ff1c",
"https://deno.land/std@0.97.0/path/win32.ts": "77f7b3604e0de40f3a7c698e8a79e7f601dc187035a1c21cb1e596666ce112f8",
"https://deno.land/x/cache@0.2.13/deps.ts": "6f14e76a1a09f329e3f3830c6e72bd10b53a89a75769d5ea886e5d8603e503e6",
"https://deno.land/x/cache@0.2.13/directories.ts": "ef48531cab3f827252e248596d15cede0de179a2fb15392ae24cf8034519994f",
"https://deno.land/x/dwm@0.3.3/mod.ts": "8a8ca602442d250eaa7cef67c14245a41aa7dc8de2fa337008e433a2ed1fe2f1",
"https://deno.land/x/dwm@0.3.3/src/core/common.ts": "dd4cd26f45fca187c5a6192bfb7b3b4a01a23c66dddf64e19e013de7748f988d",
"https://deno.land/x/dwm@0.3.3/src/core/event.ts": "715cce309021e9dcd45b7e3f41bddea961d4b157dcf6f29a21e910825aae90a8",
"https://deno.land/x/dwm@0.3.3/src/core/mod.ts": "4c54848365ea17b67e65d4d58c7c94378c9bbc6ea2a59d7d11f1d701e6a5483a",
"https://deno.land/x/dwm@0.3.3/src/core/monitor.ts": "b291ebad386095285fb7c430990be0a9f1f5f81fbcb338058ce72a538a75d667",
"https://deno.land/x/dwm@0.3.3/src/core/platform.ts": "6cab5f575198848673204673fe82d242c9c87549c16cbed9a64c838eb99dd2d4",
"https://deno.land/x/dwm@0.3.3/src/core/window.ts": "1ccd738d6e4e28836327a76480c3c47855f617fa7ed7552a035f2d7bf0fd6c6d",
"https://deno.land/x/dwm@0.3.3/src/platform/glfw/constants.ts": "832295fa6a4bd66aea638bd09ad2cc48b3756daff814c7c0ae2a544f228be9e5",
"https://deno.land/x/dwm@0.3.3/src/platform/glfw/ffi.ts": "0c6a521a8374aa8c912417edfa5c263423286363f4a7c827d4d26ead8b954ee6",
"https://deno.land/x/dwm@0.3.3/src/platform/glfw/monitor.ts": "05506c5d21c527a6ea456d24e00f88a01a9292a68f45a845499137ecb6fb80c7",
"https://deno.land/x/dwm@0.3.3/src/platform/glfw/platform.ts": "cca2684151f34be392e74a9828f89f8c3ed46db25e59aec1f638b4ccf82535e9",
"https://deno.land/x/dwm@0.3.3/src/platform/glfw/scancode_win.json": "711ee525f88fe92129acd7d66fd6a5665b68ce6a60f590ae24de67e1ee916b8f",
"https://deno.land/x/dwm@0.3.3/src/platform/glfw/window.ts": "a6dd426a95cd93ba4905da151a0d06e9376becca273ee8bc8d1c9a7bd16e0d81",
"https://deno.land/x/dwm@0.3.3/src/platform/mod.ts": "20572d937c62ec543e0ca87cf8ed32cd15505d254f97a6fae98b936e480f2157",
"https://deno.land/x/gluten@0.1.6/api/gles23.2.ts": "99cad13b74938ff987a1a707f73d72a82ddf66935e45b59d1980928cd3af3495",
"https://esm.sh/js-tokens@8.0.1": "7b08a51f91034b720edcde4f0b4314abc39ee14da57861e3e676f1ed1f4fb4ab",
"https://esm.sh/v119/js-tokens@8.0.1/deno/js-tokens.mjs": "0fa55e76fa97785f8f938db8ea55e0db57825ea81cdcad20bd925f9902f678c1",
"https://esm.sh/v119/js-tokens@8.0.1/index.d.ts": "9b178631a934bd5e4832b478d4f74083d4dc357615a0d1a632357dfafe898cdb",
"https://glfw-binaries.deno.dev/3.4.0-patch2/glfw3_darwin.js": "48911f26fff723a9c5f2f38e39be42fc65ed8dea6f2ba1f1acb464d3f0aa435b",
"https://glfw-binaries.deno.dev/3.4.0-patch2/glfw3_darwin_aarch64.js": "ae4d795d93830b8a27714ab6c20b69b67f3d4ad3544c50e344558756cf2e92f3",
"https://glfw-binaries.deno.dev/3.4.0-patch2/glfw3_linux.js": "b064aedb175fee1a977937f07584238f313a1958f9869273e7e672c42f09932d",
"https://glfw-binaries.deno.dev/3.4.0-patch2/glfw3_windows.js": "6ac603e03520c8c333e1475cb00f982adb1f8a99de7f4bb0b8953da66f210159",
"https://raw.githubusercontent.com/Nisgrak/deno-clipboard/fix-deno-1.0.0/mod.ts": "85282325a499c75c6f9ed3603fc5f8baf4bf661a616add43b4e6f033def52680",
"https://unpkg.com/js-tokens@8.0.1/index.js": "322c95254ceef0ac195f4e71adac2a90adf379a2d67fbb948402295a780fdbc0"
},
"npm": {
"specifiers": {
"js-tokens": "js-tokens@8.0.1"
},
"packages": {
"js-tokens@8.0.1": {
"integrity": "sha512-3AGrZT6tuMm1ZWWn9mLXh7XMfi2YtiLNPALCVxBCiUVq0LD1OQMxV/AdS/s7rLJU5o9i/jBZw/N4vXXL5dm29A==",
"dependencies": {}
}
}
}
}

43
deps.ts
View File

@ -1,43 +0,0 @@
// dwm
export {
createWindow,
getProcAddress,
mainloop,
} from "https://deno.land/x/dwm@0.3.3/mod.ts";
export * as gl from "https://deno.land/x/gluten@0.1.6/api/gles23.2.ts";
// jsTokens
import jsTokens from "https://esm.sh/js-tokens@8.0.1";
export function tokenize(input: string): Iterable<Token> {
// deno-lint-ignore no-explicit-any
return (jsTokens as any)(input);
}
type Token =
| { type: "StringLiteral"; value: string; closed: boolean }
| { type: "NoSubstitutionTemplate"; value: string; closed: boolean }
| { type: "TemplateHead"; value: string }
| { type: "TemplateMiddle"; value: string }
| { type: "TemplateTail"; value: string; closed: boolean }
| { type: "RegularExpressionLiteral"; value: string; closed: boolean }
| { type: "MultiLineComment"; value: string; closed: boolean }
| { type: "SingleLineComment"; value: string }
| { type: "IdentifierName"; value: string }
| { type: "PrivateIdentifier"; value: string }
| { type: "NumericLiteral"; value: string }
| { type: "Punctuator"; value: string }
| { type: "WhiteSpace"; value: string }
| { type: "LineTerminatorSequence"; value: string }
| { type: "Invalid"; value: string };
// clipboard
import { clipboard } from "https://raw.githubusercontent.com/Nisgrak/deno-clipboard/fix-deno-1.0.0/mod.ts";
export { clipboard } from "https://raw.githubusercontent.com/Nisgrak/deno-clipboard/fix-deno-1.0.0/mod.ts";
try {
await clipboard.readText();
} catch (err) {
console.log("If you are running this on linux, please make sure you have 'xsel' installed.");
throw err;
}
// path
export * as path from "https://deno.land/std@0.186.0/path/mod.ts";

View File

@ -1,134 +0,0 @@
# Faux Manual
This document is up-to-date as of May 14, 2023.
Faux is a [fantasy console](https://en.wikipedia.org/wiki/Fantasy_video_game_console) heavily inspired by [PICO-8](https://www.lexaloffle.com/pico-8.php), but with several alternative design choices. It is probably nowhere near as resource efficient either.
This console being in its infancy, this document is literally the only documentation that exists. As such, anything not found in this documentation should be asked of the author, or assumed to be similar to PICO-8.
## What's different from PICO-8?
Glad you asked.
Probably the most important difference is that cartridges are written in JavaScript rather than Lua.
Another huge design difference is that rather than having a fixed amount of sprite/map/music data, a Faux cartridge is made up of up to 16 "sheets". Each sheet can store a certain amount of data in a specific format. Sheets can be used to hold sprite data, map data, code, and eventually music/sfx, fonts, and other types of data. The first sheet must always be a code sheet and must return an object with three properties: `init`, `update`, and `draw`, each of which should be a function.
## Code
The code used in faux cartridges is JavaScript, but without a lot of the language built-ins. Instead, faux provides it's own api to accomplish things like drawing sprites, etc.
In the code editor, a few special characters can be inserted by holding alt while pressing another key. Currently, the characters that can be added in this way are:
Symbols for arrows:
- `⬆️` (Alt+W)
- `⬅️` (Alt+A)
- `⬇️` (Alt+S)
- `➡️` (Alt+D)
And math symbols:
- `π` (Alt+P)
### Graphics
- `cls(color?: number)` clears the screen to the given color if provided, otherwise, black.
- `camera(x: number, y: number)` draws everything from here on with an offset of (-x, -y).
- `sprsht(sheet: number)` sets the current spritesheet used for drawing sprites with the `spr` function below.
- `spr(x: number, y: number, sprite: number)` draws the given sprite from the current spritesheet at (x,y).
- `txt(x: number, y: number, text: string, color?: number)` draws the given text at (x,y) in the provided color (or white if none provided).
- `rectfill(x: number, y: number, w: number, h: number, color: number)` fills a rectangle with the given color with a top-left corner at (x,y) and a width of w and a height of h.
- `rect(x: number, y: number, w: number, h: number, color: number)` outlines a rectangle with the given color with a top-left corner at (x,y) and a width of w and a height of h.
- `circfill(x: number, y: number, r: number, color: number)` fills a circle with the given color with a center at (x,y) and a radius of r.
- `circ(x: number, y: number, r: number, color: number)` outlines a circle with the given color with a center at (x,y) and a radius of r.
- `ovalfill(x0: number, y0: number, x1: number, y1: number, color: number)` fills an ellipse with the given color whose bounding box has a top-left corner at (x0,y0) and a bottom-right corner at (x1,y1).
- `oval(x0: number, y0: number, x1: number, y1: number, color: number)` outlines an ellipse with the given color whose bounding box has a top-left corner at (x0,y0) and a bottom-right corner at (x1,y1).
- `pset(x: number, y: number, color: number)` sets the color of the pixel at (x,y) to the given color.
- `map(mapSheet: number, tileX: number, tileY: number, screenX: number, screenY: number, tileW: number, tileH: number)` draws the map of the given sheet to the screen at (screenX,screenY) beginning from from the tile at (tileX,tileY) and drawing tileW many tiles across, and tileH many tiles down.
### Map
- `mgetsht(mapSheet: number, x: number, y: number)` returns the sheet number of the sprite at tile (x,y) in the given map
- `mgetspr(mapSheet: number, x: number, y: number)` returns the sprite number within it's sheet of the sprite at tile (x,y) in the given map
- `mset(mapSheet: number, x: number, y: number, sprSheet: number, spr: number)` sets the sprite at tile (x,y) in the given map to the given sprite of the given spritesheet. **(THIS FUNCTION IS TEMPORARILY UNAVAILABLE.)**
### Input
- `btn(key: string | number)` returns a boolean indicating whether the given key is currently held down.
- `btnp(key: string | number)` returns a boolean indicating whether the given key has just been pressed. Fires repeatedly after a time, as when typing.
- `btnr(key: string | number)` returns a boolean indicating whether the given key has just been released.
There are also values:
- `⬆️` a number that corresponds to the up arrow.
- `⬅️` a number that corresponds to the left arrow.
- `⬇️` a number that corresponds to the down arrow.
- `➡️` a number that corresponds to the right arrow.
### System
- `save(name: string)` saves the cartridge
- `load(name: string)` loads the cartridge
- `play()` plays the cartridge
### Misc.
- `code(sheet: number)` executes the code in the given sheet as a function and returns any return value.
- `log(...args: any)` logs the given args to the stdout of faux.
### REPL Only
- `print(val: any)` only really should be used in the repl.
- `printVal(val: any)` only really should be used in the repl.
### Math functions
These are all identical to what Javascript typically has under the [`Math`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math) namespace:
- `max`
- `min`
- `floor`
- `ceil`
- `sin`
- `cos`
- `atan2`
- `sqrt`
- `abs`
- `rand`
Faux also provides:
- `π` which is just `Math.PI` in regular JS.
### JS Objects
The following JS objects/functions/value are exactly provided as is in a typical JS environment:
- [`Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
- [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
- [`Boolean`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)
- [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date)
- [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
- [`Function`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function)
- [`Infinity`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Infinity)
- [`JSON`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON)
- [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
- [`NaN`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN)
- [`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)
- [`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
- [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
- [`Proxy`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
- [`Reflect`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect)
- [`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp)
- [`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)
- [`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)
- [`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol)
- [`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap)
- [`WeakRef`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef)
- [`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet)
- [`isFinite`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
- [`isNaN`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN)
- [`eval`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval)
- [`parseFloat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat)
- [`parseInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt)

View File

@ -1,130 +0,0 @@
- [x] load
- [x] save
- [ ] folder
- [ ] ls (cd?)
- [x] run
- [ ] stop
- [ ] resume
- [ ] assert
- [ ] reboot
- [ ] reset
- [ ] info
- [ ] flip
- [x] printh (as `log`)
- [ ] time/t
- [ ] stat
- [ ] extcmd
- [ ] clip
- [x] pset
- [ ] pget
- [ ] sget
- [ ] sset
- [ ] fget
- [ ] fset
- [?] print
- [ ] cursor
- [ ] color
- [x] cls
- [x] camera
- [x] circ
- [x] circfill
- [x] oval
- [x] ovalfill
- [ ] line
- [x] rect
- [x] rectfill
- [ ] pal
- [ ] palt
- [x] spr
- [ ] sspr
- [ ] fillp
- [x] btn
- [x] btnp
- [ ] sfx
- [ ] music
- [x] mget
- [x] mset
- [x] map
- [ ] tline
- [ ] peek
- [ ] poke
- [ ] peek2
- [ ] poke2
- [ ] peek4
- [ ] poke4
- [ ] memcpy
- [ ] reload
- [ ] cstore
- [ ] memset
- [ ] menuitem
- [ ] cartdata
- [ ] dget
- [ ] dset
- [ ] serial
- [ ] setmetatable
- [ ] getmetatable
- [ ] rawset
- [ ] rawget
- [ ] rawequal
- [ ] rawlen
== most things below here handled by js or easily included.
-- js Array has most things we want here
- [ ] add
- [ ] del
- [ ] deli
- [ ] count
- [ ] all
- [ ] foreach
- [ ] pairs
- [x] max
- [x] min
- [ ] mid
- [x] flr
- [x] ceil
- [x] cos
- [x] sin
- [x] atan2
- [x] sqrt
- [x] abs
- [x] rnd
- [ ] srand
-- skipping these in favor of bitwise operations if needed
- [ ] band
- [ ] bor
- [ ] bxor
- [ ] bnot
- [ ] shl
- [ ] shr
- [ ] lshr
- [ ] rotl
- [ ] rotr
-- js comes with stuff here (String, Number, typeof, etc.)
- [ ] tostr
- [ ] tonum
- [ ] chr
- [ ] ord
- [ ] sub
- [ ] split
- [ ] type
-- js comes with stuff here
- [ ] cocreate
- [ ] coresume
- [ ] assert
- [ ] costatus
- [ ] yield

View File

@ -1,694 +0,0 @@
import { clearScreen, fillRect } from "../io/window.ts";
import { CHAR, font } from "../data/font.ts";
import { drawText, measureText } from "../runtime/builtins.ts";
import { COLOR } from "../data/colors.ts";
import { getCodeSheet, setSheet } from "../io/sheet.ts";
import { K, ctrlKeyDown, getKeyboardString, keyPressed, shiftKeyDown } from "../io/keyboard.ts";
import { clipboard, tokenize } from "../deps.ts";
import { getBuiltins } from "../runtime/runcode.ts";
import { page } from "./viewsheets.ts";
import { mouseDown, mouseHeld, mousePos } from "../io/mouse.ts";
const historyDebounceFrames = 20;
const fontHeight = font.height;
const keywords = [
"break",
"case",
"catch",
"class",
"const",
"continue",
"debugger",
"default",
"delete",
"do",
"else",
"export",
"extends",
"finally",
"for",
"function",
"if",
"import",
"in",
"instanceof",
"new",
"return",
"super",
"switch",
"this",
"throw",
"try",
"typeof",
"var",
"void",
"while",
"with",
"let",
"static",
"yield",
"await",
"enum",
"implements",
"interface",
"package",
"private",
"protected",
"public",
"=>",
];
const values = [
"false",
"null",
"true",
"undefined",
"NaN",
"Infinity",
CHAR.PI,
];
const operator = [
"&&",
"||",
"??",
"--",
"++",
".",
"?.",
"<",
"<=",
">",
">=",
"!=",
"!==",
"==",
"===",
"+",
"-",
"%",
"&",
"|",
"^",
"/",
"*",
"**",
"<<",
">>",
">>>",
"=",
"+=",
"-=",
"%=",
"&=",
"|=",
"^=",
"/=",
"*=",
"**=",
"<<=",
">>=",
">>>=",
"!",
"?",
"~",
"...",
];
const punctuation = [
"(",
")",
"[",
"]",
"{",
"}",
".",
":",
";",
",",
];
const builtinColor = COLOR.BLUE;
const keywordColor = COLOR.PURPLE;
const operatorColor = COLOR.CYAN;
const valueColor = COLOR.ORANGE;
const stringColor = COLOR.GREEN;
const regexColor = COLOR.PINK;
const punctuationColor = COLOR.LIGHTGRAY;
const commentColor = COLOR.DARKGREEN;
const identifierColor = COLOR.YELLOW;
const invalidColor = COLOR.RED;
const caretColor = COLOR.WHITE;
const selectionColor = COLOR.DARKBLUE;
const backgroundColor = COLOR.DARKERBLUE;
const tokenColors = {
"StringLiteral": stringColor,
"NoSubstitutionTemplate": stringColor,
"TemplateHead": stringColor,
"TemplateMiddle": stringColor,
"TemplateTail": stringColor,
"RegularExpressionLiteral": regexColor,
"MultiLineComment": commentColor,
"SingleLineComment": commentColor,
"IdentifierName": identifierColor,
"PrivateIdentifier": identifierColor,
"NumericLiteral": valueColor,
"Punctuator": punctuationColor,
"WhiteSpace": punctuationColor,
"LineTerminatorSequence": punctuationColor,
"Invalid": invalidColor,
}
const transformForCopy = (text: string) => {
text = text.replaceAll(CHAR.UP, "⬆️");
text = text.replaceAll(CHAR.LEFT, "⬅️");
text = text.replaceAll(CHAR.DOWN, "⬇️");
text = text.replaceAll(CHAR.RIGHT, "➡️");
return text;
}
const transformForPaste = (text: string) => {
let newstr = "";
text = text.replaceAll("⬆️", CHAR.UP);
text = text.replaceAll("⬅️", CHAR.LEFT);
text = text.replaceAll("⬇️", CHAR.DOWN);
text = text.replaceAll("➡️", CHAR.RIGHT);
for (const char of text) {
if (char in font.chars) {
newstr += char;
}
}
return newstr;
}
const state = {
doubleClickTimer: 0,
history: [] as Array<{code: string, anchor: number, focus: number}>,
historyDebounce: 0,
historyIndex: 0,
undo() {
console.log('undoing');
if (this.historyIndex === this.history.length && this.historyDebounce > 0) {
this.snapshot();
}
console.log('historyIndex', this.historyIndex);
if (this.historyIndex > 0) {
this.historyIndex -= 1;
const snap = this.history[this.historyIndex];
console.log('historyIndex', this.historyIndex);
this.code = snap.code;
this.setSelection(snap.anchor, snap.focus);
}
},
redo() {
console.log('redoing');
if (this.historyIndex < this.history.length-1) {
this.historyIndex += 1;
const snap = this.history[this.historyIndex];
this.code = snap.code;
this.setSelection(snap.anchor, snap.focus);
}
},
snapshot() {
const snap = {
code: this.code,
anchor: this.anchor,
focus: this.focus,
};
this.history.push(snap);
console.log('took snapshot', this.historyIndex, snap);
},
startSnapping() {
console.log('start snapping', this.historyIndex);
if (this.historyDebounce <= 0) {
this.historyIndex += 1;
}
if (this.history.length > this.historyIndex) {
this.history.length = this.historyIndex;
}
this.historyDebounce = historyDebounceFrames;
},
wordMode: false,
scrollX: 0,
scrollY: 0,
anchor: 0,
focus: 0,
get focusX() {return indexToGrid(this.code, this.focus).x;},
get focusY() {return indexToGrid(this.code, this.focus).y;},
get anchorX() {return indexToGrid(this.code, this.anchor).x;},
get anchorY() {return indexToGrid(this.code, this.anchor).y;},
get focusPixelX() {return indexToRect(this.code, this.focus).x;},
get focusPixelY() {return indexToRect(this.code, this.focus).y;},
get anchorPixelX() {return indexToRect(this.code, this.anchor).x;},
get anchorPixelY() {return indexToRect(this.code, this.anchor).y;},
isCollapsed() {
return this.anchor === this.focus;
},
clampInRange(n: number) {
return Math.max(0, Math.min(n, this.code.length))
},
findNearestWordBoundaryLeft(index: number) {
if (index === this.code.length-1) {
return index;
}
const words1 = this.code.slice(0, index+1).split(/\b/g);
if (words1[words1.length-1].length === 1) {
return index;
}
const words = this.code.slice(0, index).split(/\b/g);
if (!words.length) {
return 0;
}
return index-words[words.length-1].length;
},
findNearestWordBoundaryRight(index: number) {
if (index === 0) {
return index;
}
const words1 = this.code.slice(index-1).split(/\b/g);
if (words1[0].length === 1) {
return index;
}
const words = this.code.slice(index).split(/\b/g);
if (!words.length) {
return this.code.length;
}
return index+words[0].length;
},
setSelection(anchor: number | {x: number, y: number}, focus?: number | {x: number, y: number}) {
if (typeof anchor !== "number") {
anchor = gridToIndex(this.code, anchor.x, anchor.y);
}
focus = focus ?? anchor;
if (typeof focus !== "number") {
focus = gridToIndex(this.code, focus.x, focus.y);
}
this.anchor = this.clampInRange(anchor);
this.focus = this.clampInRange(focus);
if (this.wordMode) {
console.log('word mode', this.anchor, this.focus, this.findNearestWordBoundaryLeft(this.anchor), this.findNearestWordBoundaryRight(this.focus));
if (this.anchor <= this.focus) {
this.anchor = this.findNearestWordBoundaryLeft(this.anchor);
this.focus = this.findNearestWordBoundaryRight(this.focus);
} else {
this.anchor = this.findNearestWordBoundaryRight(this.anchor);
this.focus = this.findNearestWordBoundaryLeft(this.focus);
}
}
this.anchor = this.clampInRange(this.anchor);
this.focus = this.clampInRange(this.focus);
},
setFocus(focus: number | {x: number, y: number}) {
if (typeof focus !== "number") {
focus = gridToIndex(this.code, focus.x, focus.y);
}
this.focus = this.clampInRange(focus);
if (this.wordMode) {
if (this.anchor <= this.focus) {
this.anchor = this.findNearestWordBoundaryLeft(this.anchor);
this.focus = this.findNearestWordBoundaryRight(this.focus);
} else {
this.anchor = this.findNearestWordBoundaryRight(this.anchor);
this.focus = this.findNearestWordBoundaryLeft(this.focus);
}
}
this.focus = this.clampInRange(this.focus);
},
insertText(text: string) {
const {code, anchor, focus} = this;
this.code = code.slice(0, Math.min(anchor, focus)) + text + code.slice(Math.max(anchor, focus));
this.setSelection(Math.min(anchor, focus) + text.length);
this.startSnapping();
},
toggleComment() {
const lines = this.code.split("\n");
const {focusX, focusY, anchorX, anchorY} = this;
const lineInSelection = (i: number) => i >= Math.min(focusY, anchorY) && i <= Math.max(focusY, anchorY);
const allLinesAreCommented = lines.every((line, i) => {
if (lineInSelection(i) && !line.trim().startsWith("// ")) {
return false;
} else {
return true;
}
});
const newLines = lines.map((line, i) => {
if (lineInSelection(i)) {
if (allLinesAreCommented) {
return line.slice(3);
} else {
return "// "+line;
}
} else {
return line;
}
});
this.code = newLines.join("\n");
const shiftBy = allLinesAreCommented ? -3 : 3;
this.setSelection({x: anchorX+shiftBy, y: anchorY}, {x: focusX+shiftBy, y: focusY});
this.startSnapping();
},
indent(indentString: string) {
const lines = this.code.split("\n");
const {focusX, focusY, anchorX, anchorY} = this;
const newLines = lines.map((line, i) => {
if (i >= Math.min(focusY, anchorY) && i <= Math.max(focusY, anchorY)) {
return indentString+line;
} else {
return line;
}
});
this.code = newLines.join("\n");
this.setSelection({x: anchorX+1, y: anchorY}, {x: focusX+1, y: focusY});
this.startSnapping();
},
outdent(outdentRegex: RegExp) {
const lines = this.code.split("\n");
const {focusX, focusY, anchorX, anchorY} = this;
const newLines = lines.map((line, i) => {
const match = line.match(outdentRegex);
if (i >= Math.min(focusY, anchorY) && i <= Math.max(focusY, anchorY) && match) {
return line.slice(match[0].length);
} else {
return line;
}
});
this.code = newLines.join("\n");
this.setSelection({x: Math.max(0,anchorX-1), y: anchorY}, {x: Math.max(0,focusX-1), y: focusY});
this.startSnapping();
},
backspace() {
const {code, focus} = this;
if (this.isCollapsed()) {
if (focus > 0) {
this.code = code.slice(0, focus-1) + code.slice(focus);
this.setSelection(focus-1);
this.startSnapping();
}
} else {
this.insertText("");
}
},
delete() {
const {code, focus} = this;
if (this.isCollapsed()) {
if (focus < code.length) {
this.code = code.slice(0, focus) + code.slice(1+focus);
this.startSnapping();
}
} else {
this.insertText("");
}
},
async copy() {
const {code, anchor, focus} = this;
const selected = code.slice(Math.min(anchor,focus), Math.max(anchor,focus));
await clipboard.writeText(transformForCopy(selected));
},
async cut() {
await this.copy();
this.insertText("");
},
async paste() {
this.insertText(transformForPaste(await clipboard.readText()));
},
scrollToCursor() {
const {focusY, scrollY, scrollX, focus} = this;
const fh = fontHeight + 1;
const rect = indexToRect(this.code, focus);
if (focusY*fh < scrollY) {
this.scrollY = focusY*fh;
}
if (focusY*fh > scrollY+112-fh) {
this.scrollY = focusY*fh-112+fh;
}
if (rect.x < scrollX) {
this.scrollX = rect.x;
}
if (rect.x+rect.w > scrollX+128) {
this.scrollX = rect.x-128+rect.w+1;
}
},
currentIndentation() {
const lines = this.code.slice(0, this.focus).split("\n");
const line = lines[lines.length-1];
const match = line.match(/^\s*/);
if (!match) {
return "";
}
return match[0];
},
get code() {
return getCodeSheet(page.activeSheet);
},
set code(val) {
setSheet(page.activeSheet, "code", val);
}
}
const indexToGrid = (str: string, index: number) => {
const linesUpTo = str.slice(0,index).split("\n");
return {
x: linesUpTo[linesUpTo.length-1].length,
y: linesUpTo.length - 1,
}
}
const gridToIndex = (str: string, x: number, y: number) => {
const lines = str.split("\n");
if (y < 0) {
return 0;
}
if (y >= lines.length) {
return str.length;
}
return lines.slice(0, y).join("\n").length+Math.min(x, lines[y].length)+(y === 0 ? 0 : 1);
}
const indexToRect = (str: string, index: number) => {
const linesUpTo = str.slice(0,index).split("\n");
let extra = 0;
if (linesUpTo[linesUpTo.length-1].length > 0) {
extra = 1;
}
return {
x: measureText(linesUpTo[linesUpTo.length-1]) + extra,
y: (fontHeight + 1)*(linesUpTo.length - 1),
w: measureText(str[index] ?? "\n"),
h: fontHeight+1,
}
}
const pixelToIndex = (str: string, x: number, y: number) => {
const lines = str.split("\n");
if (y < 0) {
return 0;
}
if (y >= (fontHeight+1)*lines.length) {
return str.length;
}
const yy = Math.floor(y/(fontHeight+1));
const prefix = lines.slice(0, yy).join("\n").length+(yy === 0 ? 0 : 1);
const line = lines[yy];
let j = 0;
while (measureText(line.slice(0, j)) < x && j < line.length) {
j+=1;
}
if (measureText(line) < x) {
j+=1;
}
return prefix + Math.max(0, j-1);
}
const update = async () => {
const { focus } = state;
if (state.history.length === 0) {
state.snapshot();
}
if (state.historyDebounce > 0) {
state.historyDebounce -= 1;
if (state.historyDebounce <= 0) {
state.snapshot();
}
}
if (state.doubleClickTimer > 0) {
state.doubleClickTimer -= 1;
}
if (mouseDown() && !shiftKeyDown()) {
if (state.doubleClickTimer > 0) {
state.wordMode = true;
} else {
state.doubleClickTimer = 10;
}
const {x, y} = mousePos();
state.setSelection(pixelToIndex(state.code, x+state.scrollX, y+state.scrollY-8));
state.scrollToCursor();
} else if (mouseHeld()) {
const {x, y} = mousePos();
state.setFocus(pixelToIndex(state.code, x+state.scrollX, y+state.scrollY-8));
state.scrollToCursor();
} else {
state.wordMode = false;
}
const keyboardString = getKeyboardString();
if (keyboardString) {
state.insertText(keyboardString);
state.scrollToCursor();
}
if (keyPressed(K.ENTER)) {
state.insertText("\n"+state.currentIndentation());
state.scrollToCursor();
}
if (keyPressed(K.TAB)) {
if (!shiftKeyDown()) {
if (state.isCollapsed()) {
state.insertText("\t");
} else {
state.indent("\t");
}
} else {
state.outdent(/^(\t| )/);
}
state.scrollToCursor();
}
if (keyPressed(K.BACKSPACE)) {
state.backspace();
state.scrollToCursor();
}
if (keyPressed(K.DELETE)) {
state.delete();
state.scrollToCursor();
}
if (keyPressed(K.ARROW_RIGHT)) {
if (shiftKeyDown()) {
state.setFocus(focus+1);
} else {
state.setSelection(focus+1);
}
state.scrollToCursor();
}
if (keyPressed(K.ARROW_LEFT)) {
if (shiftKeyDown()) {
state.setFocus(focus-1);
} else {
state.setSelection(focus-1);
}
state.scrollToCursor();
}
if (keyPressed(K.ARROW_DOWN)) {
const rect = indexToRect(state.code, focus);
const newIndex = pixelToIndex(state.code, rect.x, rect.y+rect.h+1+1);
if (shiftKeyDown()) {
state.setFocus(newIndex);
} else {
state.setSelection(newIndex);
}
state.scrollToCursor();
}
if (keyPressed(K.ARROW_UP)) {
const rect = indexToRect(state.code, focus);
const newIndex = pixelToIndex(state.code, rect.x, rect.y-1-1);
if (shiftKeyDown()) {
state.setFocus(newIndex);
} else {
state.setSelection(newIndex);
}
state.scrollToCursor();
}
if (keyPressed("C") && ctrlKeyDown()) {
await state.copy();
state.scrollToCursor();
}
if (keyPressed("X") && ctrlKeyDown()) {
await state.cut();
state.scrollToCursor();
}
if (keyPressed("V") && ctrlKeyDown()) {
await state.paste();
state.scrollToCursor();
}
if (keyPressed("Z") && ctrlKeyDown()) {
if (shiftKeyDown()) {
state.redo();
} else {
state.undo();
}
}
if (keyPressed("Y") && ctrlKeyDown()) {
state.redo();
}
if (keyPressed("/") && ctrlKeyDown()) {
state.toggleComment();
}
}
const draw = () => {
clearScreen();
const {
scrollX,
scrollY,
anchor,
focus,
code,
} = state;
const x = 0;
const y = 8;
const w = 128;
const h = 112;
fillRect(x, y, w, h, backgroundColor);
if (anchor !== focus) {
for (let i = Math.min(anchor, focus); i < Math.max(anchor, focus); i++) {
const sel = indexToRect(code, i);
fillRect(x+sel.x-scrollX, y+sel.y-scrollY, sel.w+2, sel.h, selectionColor);
}
}
const rect = indexToRect(code, focus);
fillRect(x+rect.x-scrollX, y+rect.y-scrollY, 1, rect.h, caretColor);
const builtins = Object.keys(getBuiltins());
const tokens = [...tokenize(code)];
let cx = 0;
let cy = 0;
tokens.forEach((token) => {
if (token.type === "LineTerminatorSequence") {
cx=0;
cy+=fontHeight+1;
return;
}
const lines = token.value.split("\n");
lines.forEach((line, i) => {
let color = tokenColors[token.type];
if (builtins.includes(token.value)) {
color = builtinColor;
}
if (keywords.includes(token.value)) {
color = keywordColor;
}
if (values.includes(token.value)) {
color = valueColor;
}
if (operator.includes(token.value)) {
color = operatorColor;
}
if (punctuation.includes(token.value)) {
color = punctuationColor;
}
drawText(1+x+cx-scrollX, 1+y+cy-scrollY, line, color);
if (i === lines.length-1) {
cx += measureText(line)+1;
} else {
cx=0;
cy+=fontHeight+1;
}
});
})
}
export const codetab = {
update,
draw,
}

View File

@ -1,95 +0,0 @@
import { clearScreen, fillRect } from "../io/window.ts";
import { codetab } from "./codetab.ts";
import { spritetab } from "./spritetab.ts";
import { viewsheets, page } from "./viewsheets.ts";
import { COLOR } from "../data/colors.ts";
import { mouseClick, mousePos } from "../io/mouse.ts";
import { drawIcon } from "../runtime/builtins.ts";
import { inRect } from "../util/util.ts";
import { sheetsIcon, trashIcon } from "../data/icons.ts";
import { SheetType, setSheet } from "../io/sheet.ts";
import { nonetab } from "./nonetab.ts";
import { maptab } from "./maptab.ts";
type TabName = SheetType; // "code" | "sprite" | "map" | "sfx" | "music" | "sheet";
const buttons: Array<{update: () => void, draw: () => void}> = [];
const makeTabButton = (tabname: TabName | "sheet", x: number, y: number, icon: Array<number>) => {
buttons.push({
update() {
if (mouseClick()) {
const {x: mouseX, y: mouseY} = mousePos();
if (inRect(mouseX, mouseY, x, y, 8, 8)) {
page.tab = tabname;
}
}
},
draw() {
drawIcon(x, y, icon, page.tab === tabname ? COLOR.YELLOW : COLOR.WHITE);
}
})
}
const makeTrashButton = (x: number, y: number, icon: Array<number>) => {
buttons.push({
update() {
if (page.tab !== "sheet") {
return
}
if (mouseClick()) {
const {x: mouseX, y: mouseY} = mousePos();
if (inRect(mouseX, mouseY, x, y, 8, 8)) {
setSheet(page.activeSheet, "none", null);
page.tab = "sheet";
}
}
},
draw() {
if (page.tab !== "sheet") {
return
}
drawIcon(x, y, icon, COLOR.BLACK);
}
})
}
makeTabButton("sheet", 120, 0, sheetsIcon);
makeTrashButton(0, 0, trashIcon);
const update = () => {
buttons.forEach(button => button.update());
if (page.tab === "code") {
codetab.update();
} else if (page.tab === "spritesheet") {
spritetab.update();
} else if (page.tab === "map") {
maptab.update();
} else if (page.tab === "sheet") {
viewsheets.update();
} else if (page.tab === "none") {
nonetab.update();
}
}
const draw = () => {
clearScreen();
if (page.tab === "code") {
codetab.draw();
} else if (page.tab === "spritesheet") {
spritetab.draw();
} else if (page.tab === "map") {
maptab.draw();
} else if (page.tab === "sheet") {
viewsheets.draw();
} else if (page.tab === "none") {
nonetab.draw();
}
fillRect(0, 0, 128, 8, COLOR.RED);
fillRect(0, 120, 128, 8, COLOR.RED);
buttons.forEach(button => button.draw());
}
export const editmode = {
update,
draw,
}

View File

@ -1,213 +0,0 @@
import { clearScreen, fillRect } from "../io/window.ts";
import { drawSprite, drawText, useSpritesheet } from "../runtime/builtins.ts";
import { COLOR } from "../data/colors.ts";
import { getMapSheet, getSheet, setSheet } from "../io/sheet.ts";
import { M, mouseClick, mouseDown, mouseHeld, mousePos } from "../io/mouse.ts";
import { drawTransparentRect, drawVoidRect, inRect, reGrid } from "../util/util.ts";
import { page } from "./viewsheets.ts";
import { keyPressed, K } from "../io/keyboard.ts";
const state = {
selectedSpriteSheet: 0,
selectedSprite: 0,
viewX: 0,
viewY: 0,
dragging: false,
dragFromViewX: 0,
dragFromViewY: 0,
dragFromX: 0,
dragFromY: 0,
get spriteSheetPage() {
return Math.floor(this.selectedSprite/64);
},
set spriteSheetPage(val) {
this.selectedSprite = 64*val+this.spriteWithinPage;
},
get spriteWithinPage() {
return this.selectedSprite%64;
},
set spriteWithinPage(val) {
this.selectedSprite = 64*this.spriteSheetPage+val;
},
get map() {
return getMapSheet(page.activeSheet);
},
set map(val) {
setSheet(page.activeSheet, "map", val);
},
setInPatch(i: number, sprsheet: number, sprite: number) {
const cellVal = this.map.subgrid(this.viewX, this.viewY, patchW, patchH).values[i];
if (cellVal) {
cellVal[0] = sprsheet
cellVal[1] = sprite;
}
},
get patch() {
return this.map.subgrid(this.viewX, this.viewY, patchW, patchH);
}
}
const patchX = 0;
const patchY = 8;
const patchW = 16;
const patchH = 9;
const spriteW = 8;
const spriteH = 8;
const spriteSheetX = 0;
const spriteSheetY = 88;
const spriteSheetW = 16;
const spriteSheetH = 4;
const spriteSheetPickerX = 0;
const spriteSheetPickerY = 81;
const spriteSheetPickerW = 16;
const spriteSheetPickerH = 1;
const spriteSheetPickerTabW = 7;
const spriteSheetPickerTabH = 7;
const spriteSheetPageSwapX = 121;
const spriteSheetPageSwapY = 81;
const spriteSheetPageSwapW = 7;
const spriteSheetPageSwapH = 7;
const update = () => {
const {x: mouseX, y: mouseY} = mousePos();
const inPatch = inRect(mouseX, mouseY, patchX, patchY, patchW*spriteW, patchH*spriteH - 2);
const inSpriteSheetPicker = inRect(mouseX, mouseY, spriteSheetPickerX, spriteSheetPickerY, spriteSheetPickerW*spriteSheetPickerTabW, spriteSheetPickerH*spriteSheetPickerTabH);
const inSpriteSheet = inRect(mouseX, mouseY, spriteSheetX, spriteSheetY, spriteSheetW*spriteW, spriteSheetH*spriteH);
const inSpriteSheetPageSwap = inRect(mouseX, mouseY, spriteSheetPageSwapX, spriteSheetPageSwapY, spriteSheetPageSwapW, spriteSheetPageSwapH);
if (mouseHeld()) {
if (inPatch) {
const {x, y} = reGrid(mouseX, mouseY, patchX, patchY, spriteW, spriteH);
const cellNumber = patchW*y+x;
state.setInPatch(cellNumber, state.selectedSpriteSheet, state.selectedSprite);
}
if (inSpriteSheetPicker) {
const {x, y} = reGrid(mouseX, mouseY, spriteSheetPickerX, spriteSheetPickerY, spriteSheetPickerTabW, spriteSheetPickerTabH);
state.selectedSpriteSheet = spriteSheetPickerW*y+x;
}
if (inSpriteSheet) {
const {x, y} = reGrid(mouseX, mouseY, spriteSheetX, spriteSheetY, spriteW, spriteH);
state.spriteWithinPage = spriteSheetW*y+x;
}
} else if (mouseDown(M.MIDDLE)) {
if (inPatch) {
const {x, y} = reGrid(mouseX, mouseY, patchX, patchY, spriteW, spriteH);
state.dragging = true;
state.dragFromX = x;
state.dragFromY = y;
state.dragFromViewX = state.viewX;
state.dragFromViewY = state.viewY;
}
} else if (mouseHeld(M.MIDDLE)) {
if (state.dragging) {
const {x, y} = reGrid(mouseX, mouseY, patchX, patchY, spriteW, spriteH);
state.viewX = state.dragFromViewX - x + state.dragFromX;
state.viewY = state.dragFromViewY - y + state.dragFromY;
}
} else if (mouseClick(M.MIDDLE)) {
state.dragging = false;
} else if (mouseClick()) {
if (inSpriteSheetPageSwap) {
state.spriteSheetPage = (1+state.spriteSheetPage)%2;
}
}
if (keyPressed(K.ARROW_RIGHT)) {
state.viewX += 1;
}
if (keyPressed(K.ARROW_LEFT)) {
state.viewX -= 1;
}
if (keyPressed(K.ARROW_UP)) {
state.viewY -= 1;
}
if (keyPressed(K.ARROW_DOWN)) {
state.viewY += 1;
}
}
const outlineRect = (x: number, y: number, w: number, h: number, color: number) => {
fillRect(x, y, w, 1, color);
fillRect(x, y, 1, h, color);
fillRect(x+w-1, y, 1, h, color);
fillRect(x, y+h-1, w, 1, color);
}
const draw = () => {
const {
selectedSpriteSheet,
spriteWithinPage,
spriteSheetPage,
} = state;
clearScreen();
fillRect(0, 8, 128, 112, COLOR.DARKGRAY);
// Draw the current patch
drawVoidRect(patchX-1, patchY-1, (patchW*spriteW)+2, (patchH*spriteH)+2);
state.patch.values.forEach((val, i) => {
const spriteX = patchX+spriteW*(i%patchW);
const spriteY = patchY+spriteH*Math.floor(i/patchW);
if (!val) {
return;
}
const [sprsheet, sprite] = val;
drawTransparentRect(spriteX, spriteY, 8, 8);
if (getSheet(sprsheet).sheet_type === "spritesheet") {
useSpritesheet(sprsheet);
drawSprite(spriteX, spriteY, sprite);
}
});
// Draw the bar
fillRect(spriteSheetPickerX, spriteSheetPickerY-1, 128, 1, COLOR.BLACK);
fillRect(spriteSheetPickerX, spriteSheetPickerY, 128, 7, COLOR.DARKGRAY);
// Draw the spritesheet picker
fillRect(spriteSheetPickerX, spriteSheetPickerY, spriteSheetPickerTabW*spriteSheetPickerW, spriteSheetPickerTabW, COLOR.BLACK);
Array(spriteSheetPickerW*spriteSheetPickerH).fill(0).forEach((_, i) => {
const tabX = spriteSheetPickerX+spriteSheetPickerTabW*(i%spriteSheetPickerW);
const tabY = spriteSheetPickerY+spriteSheetPickerTabH*Math.floor(i/spriteSheetPickerW);
let color = COLOR.DARKGREEN;
if (getSheet(i).sheet_type !== "spritesheet") {
color = COLOR.BROWN;
}
if (i === page.activeSheet) {
color = COLOR.PURPLE;
}
if (i === selectedSpriteSheet) {
color = {
[COLOR.BROWN]: COLOR.TAN,
[COLOR.DARKGREEN]: COLOR.GREEN,
[COLOR.PURPLE]: COLOR.PINK,
}[color];
}
fillRect(tabX, tabY, spriteSheetPickerTabW, spriteSheetPickerTabH, color);
drawText(tabX+2, tabY+1, ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"][i]);
});
// Draw the spritesheet page swap button
fillRect(spriteSheetPageSwapX, spriteSheetPageSwapY, spriteSheetPageSwapW, spriteSheetPageSwapH, COLOR.BLUE);
drawText(spriteSheetPageSwapX+2, spriteSheetPageSwapY+1, state.spriteSheetPage.toString());
// Draw the spritesheet
fillRect(spriteSheetX, spriteSheetY, (spriteSheetW*spriteW), (spriteSheetH*spriteH), COLOR.BLACK);
if (getSheet(selectedSpriteSheet).sheet_type === "spritesheet") {
useSpritesheet(selectedSpriteSheet);
Array(64).fill(0).forEach((_, i) => {
const sprI = i+64*spriteSheetPage;
const sprX = spriteSheetX+spriteW*(i%spriteSheetW);
const sprY = spriteSheetY+spriteH*Math.floor(i/spriteSheetW);
drawSprite(sprX, sprY, sprI);
if (i === spriteWithinPage) {
outlineRect(sprX, sprY, spriteW, spriteH, COLOR.WHITE);
}
});
}
}
export const maptab = {
update,
draw,
}

View File

@ -1,62 +0,0 @@
import { clearScreen, fillRect } from "../io/window.ts";
import { drawIcon, drawText, useSpritesheet } from "../runtime/builtins.ts";
import { COLOR } from "../data/colors.ts";
import { getSheet, setSheet } from "../io/sheet.ts";
import { mouseClick, mousePos } from "../io/mouse.ts";
import { reGridWithGap } from "../util/util.ts";
import { page } from "./viewsheets.ts";
import { codeIcon, mapIcon, spriteIcon } from "../data/icons.ts";
const gridX = 8;
const gridY = 40;
const cellW = 8;
const cellH = 8;
const gapX = 8;
const gapY = 8;
const sheetTypes = ["code", "spritesheet", "map"] as const;
const defaultSheetVal = {
code: () => "",
spritesheet: () => Array(128).fill(0).map(() => Array(64).fill(0)),
map: () => Array(64*64).fill(0).map(() => [0, 0]),
none: () =>null,
}
const update = () => {
if (mouseClick()) {
const {x: mouseX, y: mouseY} = mousePos();
const g = reGridWithGap(mouseX, mouseY, gridX, gridY, cellW, cellH, gapX, gapY);
if (g) {
const {x, y: _y} = g;
const sheetType = sheetTypes[x];
setSheet(page.activeSheet, sheetType, defaultSheetVal[sheetType]());
page.tab = getSheet(page.activeSheet).sheet_type;
}
}
}
const draw = () => {
clearScreen();
useSpritesheet(page.activeSheet);
fillRect(0, 8, 128, 112, COLOR.BLACK);
drawText(4, 16, "Click an icon below to choose");
drawText(4, 16+7, "this sheet's type...");
// Draw the spritesheet
sheetTypes.forEach((sheetType, i) => {
const sx = gridX+(cellW+gapX)*(i%6);
const sy = gridY+(cellH+gapY)*Math.floor(i/6);
const icon = {
code: codeIcon,
spritesheet: spriteIcon,
map: mapIcon,
none: null,
}[sheetType];
drawIcon(sx, sy, icon, COLOR.BLUE);
});
}
export const nonetab = {
update,
draw,
}

View File

@ -1,133 +0,0 @@
import { clearScreen, fillRect } from "../io/window.ts";
import { drawSprite, drawText, useSpritesheet } from "../runtime/builtins.ts";
import { COLOR } from "../data/colors.ts";
import { getSpriteSheet, setSheet } from "../io/sheet.ts";
import { mouseClick, mouseHeld, mousePos } from "../io/mouse.ts";
import { drawTransparentRect, inRect, outlineRect, reGrid } from "../util/util.ts";
import { page } from "./viewsheets.ts";
const state = {
selectedSprite: 0,
selectedColor: 0,
get spriteSheetPage() {
return Math.floor(this.selectedSprite/64);
},
set spriteSheetPage(val) {
this.selectedSprite = 64*val+this.spriteWithinPage;
},
get spriteWithinPage() {
return this.selectedSprite%64;
},
set spriteWithinPage(val) {
this.selectedSprite = 64*this.spriteSheetPage+val;
},
get sprites() {
return getSpriteSheet(page.activeSheet);
},
set sprites(val) {
setSheet(page.activeSheet, "spritesheet", val);
}
}
const paletteX = 88;
const paletteY = 16;
const swatchW = 8;
const swatchH = 8;
const paletteW = 4;
const paletteH = 6;
const spriteX = 8;
const spriteY = 16;
const pixelW = 8;
const pixelH = 8;
const spriteW = 8;
const spriteH = 8;
const sheetX = 0;
const sheetY = 88;
const sheetW = 16;
const sheetH = 4;
const spriteSheetPageSwapX = 121;
const spriteSheetPageSwapY = 80;
const spriteSheetPageSwapW = 7;
const spriteSheetPageSwapH = 7;
const update = () => {
if (mouseHeld()) {
const {x: mouseX, y: mouseY} = mousePos();
const inPalette = inRect(mouseX, mouseY, paletteX, paletteY, paletteW*swatchW, paletteH*swatchH);
const inSprite = inRect(mouseX, mouseY, spriteX, spriteY, spriteW*pixelW, spriteH*pixelH);
const inSheet = inRect(mouseX, mouseY, sheetX, sheetY, sheetW*spriteW, sheetH*spriteH);
if (inPalette) {
const {x, y} = reGrid(mouseX, mouseY, paletteX, paletteY, swatchW, swatchH);
state.selectedColor = paletteW*y+x;
}
if (inSprite) {
const {x, y} = reGrid(mouseX, mouseY, spriteX, spriteY, pixelW, pixelH);
const pixelNumber = spriteW*y+x;
state.sprites[state.selectedSprite][pixelNumber] = state.selectedColor;
}
if (inSheet) {
const {x, y} = reGrid(mouseX, mouseY, sheetX, sheetY, spriteW, spriteH);
state.spriteWithinPage = sheetW*y+x;
}
} else if (mouseClick()) {
const {x: mouseX, y: mouseY} = mousePos();
const inSpriteSheetPageSwap = inRect(mouseX, mouseY, spriteSheetPageSwapX, spriteSheetPageSwapY, spriteSheetPageSwapW, spriteSheetPageSwapH);
if (inSpriteSheetPageSwap) {
state.spriteSheetPage = (1+state.spriteSheetPage)%2;
}
}
}
const draw = () => {
const {sprites, selectedSprite, selectedColor} = state;
clearScreen();
useSpritesheet(page.activeSheet);
fillRect(0, 8, 128, 112, COLOR.DARKGRAY);
// Draw the palette
fillRect(paletteX-1, paletteY-1, (paletteW*swatchW)+2, (paletteH*swatchH)+2, COLOR.BLACK);
Object.keys(COLOR).forEach((name, i) => {
const swatchX = paletteX+swatchW*(i%paletteW);
const swatchY = paletteY+swatchH*Math.floor(i/paletteW);
fillRect(swatchX, swatchY, swatchW, swatchH, COLOR[name as keyof typeof COLOR]);
if (name == "TRANSPARENT") {
// transparent
drawTransparentRect(swatchX, swatchY, swatchW, swatchH);
}
if (i === selectedColor) {
outlineRect(swatchX, swatchY, swatchW, swatchH, name === "WHITE" ? COLOR.BLACK : COLOR.WHITE);
}
});
// Draw the current sprite
fillRect(spriteX-1, spriteY-1, (spriteW*pixelW)+2, (spriteH*pixelH)+2, COLOR.BLACK);
drawTransparentRect(spriteX, spriteY, (spriteW*pixelW), (spriteH*pixelH));
sprites[selectedSprite].forEach((pix, i) => {
fillRect(spriteX+pixelW*(i%spriteW), spriteY+pixelH*Math.floor(i/spriteW), pixelW, pixelH, pix);
});
// Draw the spritesheet page swap button
fillRect(spriteSheetPageSwapX, spriteSheetPageSwapY, spriteSheetPageSwapW, spriteSheetPageSwapH, COLOR.BLUE);
drawText(spriteSheetPageSwapX+2, spriteSheetPageSwapY+1, state.spriteSheetPage.toString());
// Draw the spritesheet
fillRect(sheetX, sheetY-1, (sheetW*spriteW), (sheetH*spriteH)+1, COLOR.BLACK);
Array(64).fill(0).forEach((_, i) => {
const sprI = i+64*state.spriteSheetPage;
const sprX = sheetX+spriteW*(i%sheetW);
const sprY = sheetY+spriteH*Math.floor(i/sheetW);
drawSprite(sprX, sprY, sprI);
if (i === state.spriteWithinPage) {
outlineRect(sprX, sprY, spriteW, spriteH, COLOR.WHITE);
}
});
}
export const spritetab = {
update,
draw,
}

View File

@ -1,63 +0,0 @@
import { clearScreen, fillRect } from "../io/window.ts";
import { drawIcon, drawText } from "../runtime/builtins.ts";
import { COLOR } from "../data/colors.ts";
import { getSheet } from "../io/sheet.ts";
import { mouseClick, mousePos } from "../io/mouse.ts";
import { getCart } from "../io/cart.ts";
import { font } from "../data/font.ts";
import { codeIcon, spriteIcon, mapIcon } from "../data/icons.ts";
import { reGridWithGap } from "../util/util.ts";
const fontHeight = font.height;
export const page = {activeSheet: 0, tab: "sheet"};
const gridX = 8;
const gridY = 20;
const cellW = 22;
const cellH = 16;
const gapX = 8;
const gapY = 8;
const update = () => {
if (mouseClick()) {
const {x: mouseX, y: mouseY} = mousePos();
const g = reGridWithGap(mouseX, mouseY, gridX, gridY, cellW, cellH, gapX, gapY);
if (g) {
const {x, y} = g;
page.activeSheet = 4*y+x;
const sheet = getSheet(page.activeSheet);
if (!sheet) {
console.log(x, y, g);
}
page.tab = getSheet(page.activeSheet).sheet_type;
}
}
}
const draw = () => {
clearScreen();
fillRect(0, 8, 128, 112, COLOR.DARKGRAY);
// Draw the sheet grid
getCart().forEach((sheet, i) => {
const x = gridX+(cellW+gapX)*(i%4);
const y = gridY+(cellH+gapY)*Math.floor(i/4);
fillRect(x, y, cellW, cellH, i===page.activeSheet ? COLOR.PURPLE : COLOR.BLACK);
drawText(x+(cellW)/2, y+(cellH-fontHeight)/2, i.toString().padStart(2,"0"));
const icon = {
code: codeIcon,
spritesheet: spriteIcon,
map: mapIcon,
none: null,
}[sheet.sheet_type];
if (icon) {
drawIcon(x+2, y+4, icon, COLOR.WHITE);
}
});
}
export const viewsheets = {
update,
draw,
}

133
femto-lang/faux/faux.ts Normal file
View File

@ -0,0 +1,133 @@
// const STR = (s: string): StringValue => ({type: "string", value: s});
// const FN = (f: FunctionValue["value"]): FunctionValue => ({type: "function", value: f});
// const SYM = (s: string): SymbolValue => ({type: "symbol", value: s});
// const UNDEF = (): UndefinedValue => ({type: "undefined", value: null});
// const CODE = (p: CodeBlockValue["value"]): CodeBlockValue => ({type: "code", value: p});
// const THUNK = (t: ThunkValue["value"]): ThunkValue => ({type: "thunk", value: t});
// const BOOL = (b: boolean): BooleanValue => ({type: "boolean", value: b});
// console.log("HELLO");
// type SymbolValue = {
// type: "symbol",
// value: string,
// }
// type FunctionValue = {
// type: "function",
// value: (arg: Value, env: Environment, passalong: Passalong) => Result,
// }
// type StringValue = {
// type: "string",
// value: string,
// }
// type BooleanValue = {
// type: "boolean",
// value: boolean,
// }
// type UndefinedValue = {
// type: "undefined",
// value: null,
// }
// type CodeBlockValue = {
// type: "code",
// value: Array<Value>,
// }
// type ThunkValue = {
// type: "thunk",
// value: Array<Value>,
// }
// type Value =
// | SymbolValue
// | FunctionValue
// | StringValue
// | UndefinedValue
// | CodeBlockValue
// | ThunkValue
// | BooleanValue
// type Passalong = Value;
// type Result<V extends Value = Value> = {
// result: V,
// passalong: any,
// }
// type Environment = {[key: string]: Value}
// const evaluate_codeblock = (codeBlock: CodeBlockValue, env: Environment): Result => {
// let result: Result = {
// result: UNDEF(),
// passalong: UNDEF(),
// };
// const terms = [...codeBlock.value];
// while (terms.length) {
// console.log('evaluating phrase', terms);
// result = evaluate_phrase(terms, env, result.passalong);
// }
// return result;
// }
// const evaluate_phrase = (terms: Array<Value>, env: Environment, passalong: Passalong): Result => {
// let head: Result = evaluate_term(terms.shift() as Value, env, passalong);
// let pa = passalong;
// while (head.result.type === "function") {
// if (!terms.length) {
// throw 'Runtime Error: head function has no argument to be called with';
// }
// const tail: Result = evaluate_term(terms.shift() as Value, env, UNDEF());
// head = head.result.value(tail.result, env, pa);
// pa = head.passalong;
// }
// return head;
// }
// const evaluate_term = (term: Value, env: Environment, passalong: Passalong): Result => {
// if (term.type === "symbol") {
// return {
// result: env[term.value],
// passalong: UNDEF(), // TODO: this should include term.value as a "name"
// }
// } else if (term.type === "string") {
// return {
// result: term,
// passalong: UNDEF(),
// }
// } else if (term.type === "function") {
// return {
// result: term,
// passalong: UNDEF(),
// }
// } else if (term.type === "boolean") {
// return {
// result: term,
// passalong: UNDEF(),
// }
// }
// return {
// result: UNDEF(),
// passalong: UNDEF(),
// }
// }
// const my_env: Environment = {
// print: FN((arg, env, passalong) => {
// console.log(arg);
// return {
// result: UNDEF(),
// passalong: UNDEF(),
// }
// })
// }
// const my_prog: CodeBlockValue = CODE([
// SYM("print"), STR("hi"),
// ]);
// console.log(evaluate_codeblock(my_prog, my_env));

141
femto-lang/faux/trying.js Normal file
View File

@ -0,0 +1,141 @@
const STR = (s) => ({type: "string", value: s});
const FN = (f) => ({type: "function", value: f});
const SYM = (s) => ({type: "symbol", value: s});
const UNDEF = () => ({type: "undefined", value: null});
const CODE = (p) => ({type: "code", value: p});
const THUNK = (t) => ({type: "thunk", value: t});
const BOOL = (b) => ({type: "boolean", value: b});
const evaluate_codeblock = (codeBlock, env) => {
let result = {
result: UNDEF(),
passalong: {},
};
const terms = [...codeBlock.value];
while (terms.length) {
// console.log('evaluating phrase', terms);
result = evaluate_phrase(terms, env, result.passalong);
}
return result;
}
const evaluate_phrase = (terms, env, passalong) => {
let head = evaluate_term(terms.shift(), env, passalong);
let pa = passalong;
while (head.result.type === "function") {
if (!terms.length) {
throw 'Runtime Error: head function has no argument to be called with';
}
const tail = evaluate_term(terms.shift(), env, {});
head = head.result.value(tail.result, env, pa);
pa = head.passalong;
}
return head;
}
const evaluate_term = (term, env, passalong) => {
if (term.type === "symbol") {
return {
result: env[term.value],
passalong: {name: STR(term.value)}, // TODO: this should include term.value as a "name"
}
} else if (term.type === "string") {
return {
result: term,
passalong: {},
}
} else if (term.type === "function") {
return {
result: term,
passalong: {},
}
} else if (term.type === "boolean") {
return {
result: term,
passalong: {},
}
} else if (term.type === "thunk") {
return {
result: term,
passalong: {},
}
}
return {
result: UNDEF(),
passalong: {},
}
}
const my_env = {
print: FN((arg, env, passalong) => {
console.log('PRINT', arg);
return {
result: UNDEF(),
passalong: {},
}
}),
if: FN((arg, env, passalong) => {
return {
result: FN((thunk, e2, pa) => {
if (arg.type === "boolean" && arg.value) {
return {
result: evaluate_codeblock(thunk, e2),
passalong: {handled: true},
}
} else {
return {
result: UNDEF(),
passalong: {handled: false},
}
}
}),
passalong: {},
}
}),
else: FN((thunk, env, passalong) => {
if (!passalong.handled) {
return {
result: evaluate_codeblock(thunk, env),
passalong: {handled: true},
}
} else {
return {
result: UNDEF(),
passalong: {handled: true},
}
}
}),
}
`
print "hi"
if false {
print "hi2"
} else {
print "hi3"
}
set x = 10
set y = 20
set f = fn h => {
print h
print h
}
f x
for value in obj {
}
`
const my_prog = CODE([
SYM("print"), STR("hi"),
SYM("if"), BOOL(false), THUNK([
SYM("print"), STR("hi2"),
]),
SYM("else"), THUNK([
SYM("print"), STR("hi3"),
]),
]);
console.log(evaluate_codeblock(my_prog, my_env));

150
femto-lang/lexer.ts Normal file
View File

@ -0,0 +1,150 @@
// type Token = {
// type: "paren",
// value: 1 | -1,
// } | {
// type: "bracket",
// value: 1 | -1,
// } | {
// type: "brace",
// value: 1 | -1,
// } | {
// type: "number",
// value: number,
// } | {
// type: "keyword",
// value: (typeof KEYWORDS)[number],
// } | {
// type: "identifier",
// value: string,
// } | {
// type: "string",
// value: string,
// } | {
// type: "assignment-op",
// value: "=",
// }
// const KEYWORDS = [
// "let",
// "if",
// ] as const;
// const isKeyword = (str: string): str is (typeof KEYWORDS)[number] => {
// return KEYWORDS.includes(str as any);
// }
// const isMatchNestChar = (char: string): char is "(" | ")" | "[" | "]" | "{" | "}" => {
// return char === "(" || char === ")" || char === "[" || char === "]" || char === "{" || char === "}";
// }
// const matchNestType = {
// "(": "paren",
// ")": "paren",
// "[": "bracket",
// "]": "bracket",
// "{": "brace",
// "}": "brace",
// } as const
// const matchNestValue = {
// "(": 1,
// ")": -1,
// "[": 1,
// "]": -1,
// "{": 1,
// "}": -1,
// } as const
// const isSkippableChar = (char: string) => {
// return [" ", "\n", "\t", ";"].includes(char);
// }
// const isAlpha = (char: string) => {
// return /^[a-z]$/.test(char);
// }
// const isNumeric = (char: string) => {
// return /^\d$/.test(char);
// }
// const isAlphaNumeric = (char: string) => {
// return isAlpha(char) || isNumeric(char);
// }
// const tokenize = (source: string) => {
// const tokens: Array<Token> = [];
// let src = [...source];
// while (src.length) {
// const char = src[0];
// if (isMatchNestChar(char)) {
// const token = {type: matchNestType[char], value: matchNestValue[char]};
// tokens.push(token);
// src.shift();
// } else if (char === "=") {
// const token = {type: "assignment-op", value: "="} as const;
// tokens.push(token);
// src.shift();
// } else {
// if (isSkippableChar(char)) {
// src.shift();
// } else if (isNumeric(char)) {
// let num = "";
// while (src.length && isNumeric(src[0])) {
// num += src.shift();
// }
// const token = {type: "number" as const, value: Number(num)};
// tokens.push(token);
// } else if (isAlpha(char)) {
// let ident = "";
// while (src.length && isAlphaNumeric(src[0])) {
// ident += src.shift();
// }
// if (isKeyword(ident)) {
// const token = {type: "keyword" as const, value: ident};
// tokens.push(token);
// } else {
// const token = {type: "identifier" as const, value: ident};
// tokens.push(token);
// }
// } else if (char === '"' || char === "'") {
// console.log('lexing a string');
// const q = char;
// src.shift();
// let s = "";
// while (src.length && src[0] !== q) {
// const c = src.shift();
// console.log(`c: "${c}"`);
// if (c === "\\") {
// s += src.shift();
// } else {
// s += c;
// }
// }
// if (src.length) {
// src.shift();
// }
// const token = {type: "string" as const, value: s};
// tokens.push(token);
// } else {
// throw `Unrecognized character: '${char}'`
// }
// }
// }
// return tokens;
// }
// const code = `
// let x = 45;
// let y = ( 10 );
// if (y) {
// let z = (x = y);
// }
// let say = "Hello, \\"world\\"!";
// `
// console.log(tokenize(code));

107
femto-lang/oddlang.js Normal file
View File

@ -0,0 +1,107 @@
// const STR = (s) => ({type: "string", value: s});
// const FN = (f) => ({type: "function", value: f});
// const NUL = () => ({type: "null", value: null});
// const SYM = (s) => ({type: "symbol", value: s});
// const UNDEF = () => ({type: "undefined", value: null});
// const PROG = (p) => ({type: "program", value: p});
// const THUNK = (t) => ({type: "thunk", value: t});
// const BOOL = (b) => ({type: "boolean", value: b});
// const my_prog = [
// SYM("print"), STR("hi"),
// SYM("if"), BOOL(false), THUNK([
// SYM("print"), STR("hi2"),
// ]),
// SYM("else"), THUNK([
// SYM("print"), STR("hi3"),
// ]),
// ];
// const my_env = {
// print: FN((arg) => {
// console.log(arg.value);
// return {result: UNDEF()};
// }),
// if: FN((arg) => {
// if (arg.type === "boolean" && arg.value) {
// return {
// result: FN((thunk) => {
// return {
// result: eval_program(thunk.value, my_env).result,
// handled: BOOL(true),
// };
// })
// };
// }
// return {
// result: UNDEF(),
// handled: BOOL(false),
// };
// }),
// else: FN((arg, passalong) => {
// console.log('ELSE', arg, passalong);
// if (passalong.handled === false) {
// return {
// result: eval_program(arg.value, my_env).result,
// };
// }
// return {
// result: UNDEF(),
// };
// }),
// }
// const debugLog = (...args) => {
// // console.log(args);
// }
// const eval_program = (program, env) => {
// debugLog('evaluating program');
// let val = {result: UNDEF()};
// while (program.length) {
// val = eval_phrase(program, env, val);
// }
// debugLog('program evaluated to', val);
// return val;
// }
// const eval_phrase = (program, env, passalong) => {
// debugLog('evaluating phrase');
// const phraseStart = program.shift();
// let head = eval_expression(phraseStart, env, passalong);
// while (program.length && head.result.type === "function") {
// debugLog('head', head);
// const tail = eval_expression(program.shift(), env, head);
// debugLog('tail', tail);
// head = head.result.value(tail.result, passalong, tail);
// }
// debugLog('end of phrase, result:', head, 'start:', phraseStart);
// return head;
// }
// const eval_expression = (expr, env) => {
// debugLog('evaluating expression', expr);
// let result = {result: UNDEF()};
// if (expr.type === "symbol") {
// result = {
// result: env[expr.value],
// name: STR(expr.value),
// }
// } else if (expr.type === "string") {
// result = {
// result: expr,
// }
// } else if (expr.type === "boolean") {
// result = {
// result: expr,
// }
// } else if (expr.type === "thunk") {
// result = {
// result: expr,
// }
// }
// debugLog('expression evaluated to', result);
// return result;
// }
// console.log(eval_program(my_prog, my_env));

233
ideas.md Normal file
View File

@ -0,0 +1,233 @@
A game is comprised of up to 16 "bags", each bag being exactly 8196 characters (8 kibibytes)
The first bag is the "core" of the game, and is what executes on startup.
It may include code from other bags.
bags can contain arbitrary data, but the built-in system allows convenient usage of data in specific forms.
The main uses of data are:
1. code
2. planar grid (sprites, maps, etc.)
3. sounds
(5.5 colors * 1.5 saturations + 1 gray) * 3.5 brightnesses
red 2 3
yellow/orange 2 4
green 2 3
blue 2 3
purple 1 3
gray 1 4
6 + 8 + 6 + 6 + 3 + 4 = 33
"data" can refer to a sprite or a sound
## In PICO
A sprite is:
- an 8x8 grid of values each of which is: 4 bits,
- and 8 1-bit flags
that is: 64x4 = 32x8 = 32 bytes
A sound is:
- an array of 32 notes each of which is: pitch(0-63), volume(0-7), instrument(0-15?), effect(0-7),
- 5 flags: 0-1, 0-1, 0-2, 0-2, 0-2
that is: 32x(6+3+4+3) = 32x16 = 64x8 = 64 bytes
## In FEMTO
A sprite is:
- an 8x8 grid of values each of which is: color(0-31), 3 unused bits
that is: 64x8 = 64 bytes
A sound is:
- an array of 16 notes each of which is: pitch(0-63), volume(0-7), instrument(0-15?), effect(0-7),
that is: 16(6+3+4+3) = 16x16 = 32x8 = 32 bytes
A "block" is 64 bytes = 0x40
A "sheet" is 64 blocks = 4096 bytes = 4KiB = 0x1000
A sound-sheet, a sprite-sheet, a code-sheet, a map-sheet
A full map is:
- 128x128 with values from 0-255
A quarter-map is:
- 64x64 grid of values each of which is 8 bits
This is equivalent to a "sheet": the "blocks" are 8x8 regions
What if we allow a "meta-sheet" which contains metadata for other blocks.
Each block in a different sheet is associated with a single byte here.
That means this has 64 sheets' worth of metadata.
A meta-sheet is:
- each block is 64 bytes: one byte for each block of a different sheet. -- the hooking up happens separately
Your package can be comprised of up to 64 sheets (= 256KiB = 0.25MiB)
Each sheet can be accessed by an id 0-63. Each block in a sheet can be accessed by an id 0-63.
Sheet 0 is the entrypoint and is the code that starts running.
draw_sprite(sheet_id, block_id)
play_sound(sheet_id, block_id)
map_get(sheet_id, block_id, x, y)
## The Language
Considering a functional language idea.
We have an IO "monad"?
type systems seem complicated... so we'll skip that for now.
functions are variables.
```
// JSON5 + arrow functions
set {succ: (n) => {
for (key: value in obj) {
}
if (condition) {
// do stuff
}
elseif (cond2) {
// different stuff
}
else {
// more stuff
}
return +(n, 1)
}}
```
If a function is called with the
```
funcname (arg1, arg2) {
// block here
}
```
syntax, then contents of the block can be called by calling `thunk()`.
Each function can also prepare for a chain, by calling `passalong(value)`, and the very next function call can read it with `passalong()`.
```
:x 40
:x 50
obj = {
abc: "def",
ghi: "jkl"
}
arr = [
"foo",
"bar"
]
succ = (n) => +(n, 1)
succ(n)
myif = (cond) => if(cond, thunk)
map(obj, (key, value) =>
if(eq(key, "abc"),
"overridden",
value
)
)
```
Maybe just use lua, js, or lisp after all.
Main downsides of lua: I don't love the function syntax and lack of curly braces.
Downsides of lisp: syntax is hard to get used to.
Maybe: js-like.
So:
- arrow functions
- JSON5 object syntax
- if/else with js syntax
- for with `for (key: value in obj)` OR `for (value in obj)` OR `for (key: in obj)`
- break and continue
- while with js syntax
No `this`.
```
x = 5;
while(condition, () => {
// do stuff
});
if(equal(x, 5), () => {
x = +(x, 1);
});
foreach(obj, (value, key) => {
// do stuff
});
```
```
if cond {
}
elseif cond2 {
}
else {
}
```
Eval strategy: eval current thing. If current thing is function, then eval next thing, and apply the func to that next thing. If current thing is function, eval next thing, and apply the func to that next thing. repeat. Do that if `return-and-call` was used, otherwise, if just `return` was used, move on to evaluate the next thing.
You can pass along certain things, e.g. "if" can say "i ran" or "i didn't run", and the "else" can pick that up and run with it.
You can also set a flag that says "I'm the end of this statement"
The pass-along can also be used to implement setting a variable, like `x = 5`, since the `x` can pass along its name, then the `=` can set it, and end after the `5`.
In general, anything infix can work that way, but precedence won't be right. E.g. `x = x + 5` will set `x = x`, and then add 5 to the result of that assignment, and return, but without updating `x`.
```
for val in obj {
}
for key : val in obj {
}
for key : in obj {
}
```
Functions are created with `fn var thunk`, or `var => thunk`
Properties can be accessed and set with `obj . prop`
Command is:
```
set x = 5
if condition {
// ...
}
```

250
index.html Normal file
View File

@ -0,0 +1,250 @@
<html>
<head>
<title></title>
<style>
.swatch {
width: 100px;
height: 100px;
background-color: hsl(var(--hue), var(--saturation), var(--lightness));
}
.h1p {
--hue: 310;
}
.h1 {
--hue: 340;
}
.h1s {
--hue: 335;
}
.h2d {
--hue: 50;
}
.h2 {
--hue: 37;
}
.h2s {
--hue: 30;
}
.h2h {
--hue: 57;
}
.h3 {
--hue: 130;
}
.h3s {
--hue: 145;
}
.h3h {
--hue: 203;
}
.h4 {
--hue: 224;
}
/* .h4hs {
--hue: 228;
}
.h4s {
--hue: 235;
} */
.h4hs {
--hue: 235;
}
.h4s {
--hue: 240;
}
.h5 {
--hue: 250;
}
.h6 {
--hue: 230;
}
.h7 {
--hue: 30;
}
.sp {
--saturation: 90%;
}
.s1 {
--saturation: 85%;
}
.s1x {
--saturation: 75%;
}
.sx {
--saturation: 65%;
}
.smx {
--saturation: 60%;
}
.sm {
--saturation: 55%;
}
.smm {
--saturation: 50%;
}
.s2 {
--saturation: 45%;
}
.ss {
--saturation: 40%;
}
.sl {
--saturation: 25%;
}
.s3 {
--saturation: 13%;
}
.l0 {
--lightness: 95%;
}
.l1 {
--lightness: 82%;
}
.l1h {
--lightness: 75%;
}
.l1hh {
--lightness: 70%;
}
.l2 {
--lightness: 67%;
}
.l2m {
--lightness: 62%;
}
.lm {
--lightness: 58%;
}
.l3 {
--lightness: 50%;
}
.l3h {
--lightness: 40%;
}
.l4 {
--lightness: 30%;
}
.l4h {
--lightness: 25%;
}
.l5 {
--lightness: 20%;
}
.l6 {
--lightness: 5%;
}
.row {
display: flex;
}
</style>
</head>
<body>
<div class="row">
<div class="swatch h6 s3 l0"></div>
<div class="swatch h6 s3 l2"></div>
<div class="swatch h6 s3 l4"></div>
<div class="swatch h6 s3 l6"></div>
</div>
<div class="row">
<div class="swatch h2 smx l3"></div>
<div class="swatch h7 ss l2"></div>
<div class="swatch h7 ss l3h"></div>
<div class="swatch h7 ss l4h"></div>
</div>
<div class="row">
<div class="swatch h5 smx l2"></div>
<div class="swatch h1p smx l2"></div>
<div class="swatch h1 smx l3"></div>
<div class="swatch h1s smx l4"></div>
</div>
<div class="row">
<div class="swatch h2h sp l2m"></div>
<div class="swatch h3 smx l3"></div>
<div class="swatch h3s smx l4"></div>
<div class="swatch h3s smx l5"></div>
</div>
<div class="row">
<div class="swatch h3h sp l2"></div>
<div class="swatch h4 smx l3"></div>
<div class="swatch h4hs smx l3h"></div>
<div class="swatch h4s smx l4"></div>
</div>
<!-- -->
<!-- <div class="row">
<div class="swatch h1 smx l3"></div>
<div class="swatch h1s smx l4"></div>
</div>
<div class="row">
<div class="swatch h2h sx lm"></div>
<div class="swatch h3 smx l3"></div>
<div class="swatch h3s smx l4"></div>
<div class="swatch h3s smx l5"></div>
</div>
<div class="row">
<div class="swatch h4 smx l3"></div>
<div class="swatch h4hs smx l3h"></div>
<div class="swatch h4s smx l4"></div>
</div>
<div class="row">
<div class="swatch h7 ss l4h"></div>
<div class="swatch h2s ss l3h"></div>
<div class="swatch h2s ss l2"></div>
</div>
<div class="row">
<div class="swatch h6 s3 l0"></div>
<div class="swatch h6 s3 l2"></div>
<div class="swatch h6 s3 l4"></div>
<div class="swatch h6 s3 l6"></div>
</div> -->
<!-- -->
<!-- <div class="row">
<div class="swatch h1 smx l2"></div>
<div class="swatch h1 smx l3"></div>
<div class="swatch h1s smx l4"></div>
<div class="swatch h1s smx l5"></div>
</div>
<div class="row">
<div class="swatch h2 smx l2"></div>
<div class="swatch h2 smx l3"></div>
<div class="swatch h2s smx l4"></div>
<div class="swatch h2s smx l5"></div>
</div>
<div class="row">
<div class="swatch h3 smx l2"></div>
<div class="swatch h3 smx l3"></div>
<div class="swatch h3s smx l4"></div>
<div class="swatch h3s smx l5"></div>
</div>
<div class="row">
<div class="swatch h4 smx l2"></div>
<div class="swatch h4 smx l3"></div>
<div class="swatch h4s smx l4"></div>
<div class="swatch h4s smx l5"></div>
</div>
<div class="row">
<div class="swatch h5 sl lm"></div>
<div class="swatch h5 sl l3h"></div>
<div class="swatch h5 sl l4h"></div>
</div>
<div class="row">
<div class="swatch h6 s3 l0"></div>
<div class="swatch h6 s3 l1"></div>
<div class="swatch h6 s3 l2"></div>
<div class="swatch h6 s3 l3"></div>
<div class="swatch h6 s3 l4"></div>
<div class="swatch h6 s3 l5"></div>
<div class="swatch h6 s3 l6"></div>
</div>
<div class="row">
<div class="swatch h7 ss l1"></div>
<div class="swatch h7 ss l2"></div>
<div class="swatch h7 ss l3"></div>
<div class="swatch h7 ss l4"></div>
<div class="swatch h7 ss l5"></div>
</div> -->
</body>
</html>

View File

@ -1,64 +0,0 @@
import {
mainloop,
frame,
clearScreen,
} from "./io/window.ts";
import { runCode } from "./runtime/runcode.ts";
import { getCodeSheet } from "./io/sheet.ts";
import { refreshKeyboard, keyPressed, K } from "./io/keyboard.ts";
import { repl, resetRepl } from "./repl/repl.ts";
import { addToContext } from "./runtime/runcode.ts";
import { editmode } from "./editor/editmode.ts";
import { refreshMouse } from "./io/mouse.ts";
import { camera } from "./runtime/builtins.ts";
// deno-lint-ignore no-explicit-any
let game: any = null;
let mode: "play" | "edit" | "repl" = "repl";
addToContext("play", async () => {
game = await runCode(getCodeSheet(0));
mode = "play";
game.init();
});
clearScreen();
await mainloop(async (_t) => {
// TODO: use t
if (keyPressed(K.ESCAPE)) {
const modeTo = ({
play: "repl",
edit: "repl",
repl: "edit",
} as const)[mode];
if (mode === "play") {
resetRepl();
}
if (mode === "edit") {
clearScreen();
}
mode = modeTo;
} else {
if (mode === "play") {
if (game) {
await game.update();
await game.draw();
}
frame();
} else if (mode === "repl") {
repl.update();
camera(0, 0);
repl.draw();
frame();
} else if (mode === "edit") {
await editmode.update();
camera(0, 0);
editmode.draw();
frame();
}
}
refreshKeyboard();
refreshMouse();
}, false);

View File

@ -1,28 +0,0 @@
import { path } from "../deps.ts";
import initialCart from "../data/initialCart.json" assert { type: "json" };
import { Sheet } from "./sheet.ts";
const extension = ".faux";
let staticCart = initialCart as Array<Sheet>;
let cart: Array<Sheet> = JSON.parse(JSON.stringify(staticCart));
const virtualPathToRealPath = (virtualFname: string) => {
const vfname = virtualFname + extension;
const realPath = path.join(".", "carts", ...vfname.split("/"));
return realPath;
}
export const saveCart = async (fname: string) => {
await Deno.writeTextFile(virtualPathToRealPath(fname), JSON.stringify(getCart()));
}
export const loadCart = async (fname: string) => {
const json = await Deno.readTextFile(virtualPathToRealPath(fname));
staticCart = JSON.parse(json);
cart = JSON.parse(json);
}
export const getCart = () => {
return cart;
}

View File

@ -1,174 +0,0 @@
import { font, CHAR } from "../data/font.ts";
const keyboard = new Map<number, {first: boolean, repeat: boolean, held: boolean}>();
export const K = {
ESCAPE: 256,
ENTER: 257,
TAB: 258,
BACKSPACE: 259,
INSERT: 260,
DELETE: 261,
ARROW_RIGHT: 262,
ARROW_LEFT: 263,
ARROW_DOWN: 264,
ARROW_UP: 265,
PAGE_UP: 266,
PAGE_DOWN: 267,
HOME: 268,
END: 269,
CAPS_LOCK: 280,
F1: 290,
F2: 291,
F3: 292,
F4: 293,
F5: 294,
F6: 295,
F7: 296,
F8: 297,
F9: 298,
F10: 299,
F11: 300,
F12: 301,
SHIFT_LEFT: 340,
CTRL_LEFT: 341,
ALT_LEFT: 342,
SHIFT_RIGHT: 344,
CTRL_RIGHT: 345,
ALT_RIGHT: 346,
}
export const shiftMap = {
"1": "!",
"2": "@",
"3": "#",
"4": "$",
"5": "%",
"6": "^",
"7": "&",
"8": "*",
"9": "(",
"0": ")",
"`": "~",
"-": "_",
"=": "+",
"[": "{",
"]": "}",
"\\": "|",
";": ":",
"'": '"',
",": "<",
".": ">",
"/": "?",
}
export const altMap = {
"w": CHAR.UP,
"a": CHAR.LEFT,
"s": CHAR.DOWN,
"d": CHAR.RIGHT,
"p": CHAR.PI,
}
addEventListener("keydown", (evt) => {
// console.log("keydown", evt.key, evt.key.charCodeAt(0));
const key = evt.key.charCodeAt(0);
const isRepeat = keyboard.has(key) && keyboard.get(key)?.held!;
keyboard.set(key, {
first: !isRepeat,
repeat: isRepeat,
held: true,
});
});
addEventListener("keyup", (evt) => {
// console.log("keyup", evt.key, evt.key.charCodeAt(0));
const key = evt.key.charCodeAt(0);
keyboard.set(key, {
first: false,
repeat: false,
held: false,
});
});
export const refreshKeyboard = () => {
keyboard.forEach(({held}, key) => {
if (!held) {
keyboard.delete(key);
} else {
keyboard.set(key, {
first: false,
repeat: false,
held: true,
});
}
})
}
export const keyPressed = (key: string | number) => {
if (typeof key === "string") {
key = key.toUpperCase().charCodeAt(0);
}
return keyboard.has(key) && (keyboard.get(key)?.first! || keyboard.get(key)?.repeat!);
}
export const keyDown = (key: string | number) => {
if (typeof key === "string") {
key = key.toUpperCase().charCodeAt(0);
}
return keyboard.has(key) && keyboard.get(key)?.held!;
}
export const shiftKeyDown = () => {
return keyDown(K.SHIFT_LEFT) || keyDown(K.SHIFT_RIGHT);
}
export const ctrlKeyDown = () => {
return keyDown(K.CTRL_LEFT) || keyDown(K.CTRL_RIGHT);
}
export const altKeyDown = () => {
return keyDown(K.ALT_LEFT) || keyDown(K.ALT_RIGHT);
}
export const keyReleased = (key: string | number) => {
if (typeof key === "string") {
key = key.toUpperCase().charCodeAt(0);
}
return keyboard.has(key) && !keyboard.get(key)?.held!;
}
export const getKeysPressed = () => {
const result = [...keyboard.entries()].filter(([_key, value]) => {
return value.first || value.repeat;
}).map(([key]) => key);
return result;
}
export const getKeyboardString = () => {
let str = "";
if (ctrlKeyDown()) {
return str;
}
for (const key of getKeysPressed()) {
let char = String.fromCharCode(key).toLowerCase();
if (shiftKeyDown()) {
if (char in shiftMap) {
char = shiftMap[char as keyof typeof shiftMap];
} else {
char = char.toUpperCase();
}
}
if (altKeyDown()) {
if (char in altMap) {
char = altMap[char as keyof typeof altMap];
} else {
char = char.toUpperCase();
}
}
if (char in font.chars) {
str += char;
}
}
return str;
}

View File

@ -1,121 +0,0 @@
import { WindowMouseEvent } from "https://deno.land/x/dwm@0.3.3/mod.ts";
import { gameWindow } from "./window.ts";
export const M = {
NONE: -1,
LEFT: 0,
RIGHT: 1,
MIDDLE: 2,
}
const mouseButtonsDown = {
[M.LEFT]: false,
[M.RIGHT]: false,
[M.MIDDLE]: false,
};
type MouseEventType = "click" | "down" | "up" | "move" | "dblclick";
const mouseEvents: Array<{
type: MouseEventType,
button: typeof M[keyof typeof M],
x: number,
y: number,
prevX?: number,
prevY?: number
}> = [];
let mouseX = 0;
let mouseY = 0;
const eventPixelCoords = (evt: WindowMouseEvent) => {
const {width, height} = gameWindow.size;
const min = Math.min(width, height);
const pixX = Math.floor(128*(evt.clientX-(width-min)/2)/min);
const pixY = Math.floor(128*(evt.clientY-(height-min)/2)/min);
if (pixX < 0 || pixX > 128 || pixY < 0 || pixY > 128) {
return null;
}
return {
x: pixX,
y: pixY,
}
}
const pushEvent = (type: MouseEventType, evt: WindowMouseEvent, extra?: Partial<typeof mouseEvents[0]>) => {
const coords = eventPixelCoords(evt);
if (!coords) {
return
}
mouseEvents.push({type, button: evt.button, ...coords, ...(extra ?? {})});
}
const evtInBounds = (evt: WindowMouseEvent) => {
return !!eventPixelCoords(evt);
}
addEventListener("dblclick", (evt) => {
pushEvent("dblclick", evt);
});
addEventListener("click", (evt) => {
pushEvent("click", evt);
});
addEventListener("mousedown", (evt) => {
if (evtInBounds(evt)) {
mouseButtonsDown[evt.button] = true;
}
pushEvent("down", evt);
});
addEventListener("mouseup", (evt) => {
if (evtInBounds(evt)) {
mouseButtonsDown[evt.button] = false;
}
pushEvent("up", evt);
});
addEventListener("mousemove", (evt) => {
const coords = eventPixelCoords(evt);
pushEvent("up", evt, {prevX: mouseX, prevY: mouseY});
if (coords) {
mouseX = coords.x;
mouseY = coords.y;
}
});
export const mousePos = () => {
return {
x: mouseX,
y: mouseY,
}
}
export const getMouseX = () => {
return mouseX;
}
export const getMouseY = () => {
return mouseY;
}
export const refreshMouse = () => {
mouseEvents.length = 0;
}
export const mouseDown = (button: number = M.LEFT) => {
return mouseEvents.some(ev => ev.button === button && ev.type === "down");
}
export const mouseClick = (button: number = M.LEFT) => {
return mouseEvents.some(ev => ev.button === button && ev.type === "click");
}
export const mouseDoubleClick = (button: number = M.LEFT) => {
return mouseEvents.some(ev => ev.button === button && ev.type === "dblclick");
}
export const mouseHeld = (button: number = M.LEFT) => {
return mouseButtonsDown[button];
}

View File

@ -1,56 +0,0 @@
import { getCart } from "./cart.ts";
import { LinearGrid } from "../util/util.ts";
// import { runCode, addToContext } from "./runcode.ts";
// "code" | "spritesheet" | "map" | "sfx" | "patterns" | "fonts"
export type Sheet = {
sheet_type: "code",
value: string,
} | {
sheet_type: "spritesheet",
value: Array<Array<number>>,
} | {
sheet_type: "map",
value: Array<[number, number]>,
} | {
sheet_type: "none",
value: null,
}
export type SheetType = Sheet["sheet_type"];
export const getSheet = (n: number): Sheet => {
return getCart()[n];
}
// deno-lint-ignore no-explicit-any
export const setSheet = (n: number, type: SheetType, value: any) => {
return getCart()[n] = {sheet_type: type, value};
}
export const getCodeSheet = (sheet: number) => {
const {sheet_type, value} = getSheet(sheet);
if (sheet_type !== "code") {
throw "Trying to use a non-code sheet as code."
}
return value;
}
export const getSpriteSheet = (sheet: number) => {
const {sheet_type, value} = getSheet(sheet);
if (sheet_type !== "spritesheet") {
throw Error("Trying to use a non-sprite sheet as a spritesheet.");
}
while (value.length < 128) {
value.push(Array(64).fill(0));
}
return value;
}
export const getMapSheet = (sheet: number) => {
const {sheet_type, value} = getSheet(sheet);
if (sheet_type !== "map") {
throw "Trying to use a non-map sheet as a map."
}
sheet_type
return LinearGrid(value, 64);
}

View File

@ -1,256 +0,0 @@
import {
createWindow,
getProcAddress,
gl,
} from "../deps.ts";
export {mainloop} from "../deps.ts";
import { COLOR, palette } from "../data/colors.ts";
export const gameWindow = createWindow({
title: "Faux",
width: 512,
height: 512,
resizable: true,
glVersion: [3, 2],
gles: true,
});
gl.load(getProcAddress);
function loadShader(type: number, src: string) {
const shader = gl.CreateShader(type);
gl.ShaderSource(
shader,
1,
new Uint8Array(
new BigUint64Array([
BigInt(
Deno.UnsafePointer.value(
Deno.UnsafePointer.of(new TextEncoder().encode(src)),
),
),
]).buffer,
),
new Int32Array([src.length]),
);
gl.CompileShader(shader);
const status = new Int32Array(1);
gl.GetShaderiv(shader, gl.COMPILE_STATUS, status);
if (status[0] === gl.FALSE) {
const logLength = new Int32Array(1);
gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, logLength);
const log = new Uint8Array(logLength[0]);
gl.GetShaderInfoLog(shader, logLength[0], logLength, log);
console.log(new TextDecoder().decode(log));
gl.DeleteShader(shader);
return 0;
}
return shader;
}
const vShaderSrc = `
attribute vec4 vPosition;
attribute vec4 vCol;
varying vec4 color;
void main() {
gl_Position = vPosition;
color = vCol;
}
`;
const fShaderSrc = `
precision mediump float;
varying vec4 color;
void main() {
gl_FragColor = color;
}
`;
const vShader = loadShader(gl.VERTEX_SHADER, vShaderSrc);
const fShader = loadShader(gl.FRAGMENT_SHADER, fShaderSrc);
const program = gl.CreateProgram();
gl.AttachShader(program, vShader);
gl.AttachShader(program, fShader);
gl.BindAttribLocation(program, 0, new TextEncoder().encode("vPosition\0"));
gl.BindAttribLocation(program, 1, new TextEncoder().encode("vCol\0"));
gl.LinkProgram(program);
const status = new Int32Array(1);
gl.GetProgramiv(program, gl.LINK_STATUS, status);
if (status[0] === gl.FALSE) {
const logLength = new Int32Array(1);
gl.GetProgramiv(program, gl.INFO_LOG_LENGTH, logLength);
const log = new Uint8Array(logLength[0]);
gl.GetProgramInfoLog(program, logLength[0], logLength, log);
console.log(new TextDecoder().decode(log));
gl.DeleteProgram(program);
Deno.exit(1);
}
gl.ClearColor(0.0, 0.0, 0.0, 1.0);
const pixelsPerRow = 128;
const top = 1;
const left = -1;
const cell = 2/pixelsPerRow;
const getHalfAsInt = (n: number) => Number(parseInt(Math.floor(n/2).toString()));
addEventListener("resize", (event) => {
const {width, height} = event;
const min = Math.min(width, height);
gl.Viewport(getHalfAsInt(width-min), getHalfAsInt(height-min), min, min);
});
const px = (x: number, y: number) => {
// deno-fmt-ignore
return [
left + x*cell, top - y*cell, 0,
left + (x+1)*cell, top - y*cell, 0,
left + x*cell, top - (y+1)*cell, 0,
left + (x+1)*cell, top - y*cell, 0,
left + x*cell, top - (y+1)*cell, 0,
left + (x+1)*cell, top - (y+1)*cell, 0,
];
}
const paletteX6 = palette.map(rgba => [...rgba, ...rgba, ...rgba, ...rgba, ...rgba, ...rgba]);
const c = (n: number) => {
return paletteX6[n];
}
const allPixelTriangles = new Float32Array(
Array(pixelsPerRow*pixelsPerRow).fill(null).flatMap((_, i) => px(i%pixelsPerRow,Math.floor(i/pixelsPerRow)))
)
const allPixelColors = new Float32Array(
Array(pixelsPerRow*pixelsPerRow).fill(null).flatMap(() => c(1))
)
export const cameraPos = {
x: 0,
y: 0,
}
export const setPixelColorRaw = (x: number, y: number, color: number) => {
if (x < 0 || y < 0 || x > 127 || y > 127) {
return;
}
if (color !== 0) {
const col = c(color);
allPixelColors.set(col, 4*6*(128*y+x));
}
}
export const setPixelColor = (x: number, y: number, color: number) => {
return setPixelColorRaw(Math.floor(x - cameraPos.x), Math.floor(y - cameraPos.y), color);
}
export const setPixelsInRect = (x: number, y: number, w: number, pixels: Array<number>) => {
for (let i = 0; i < pixels.length; i++) {
setPixelColor(x+i%w, y+Math.floor(i/w), pixels[i]);
}
}
export const setPixelsInRectRaw = (x: number, y: number, w: number, pixels: Array<number>) => {
for (let i = 0; i < pixels.length; i++) {
setPixelColorRaw(x+i%w, y+Math.floor(i/w), pixels[i]);
}
}
export const fillRect = (x: number, y: number, w: number, h: number, color: number) => {
setPixelsInRect(x, y, w, Array(w*h).fill(color));
}
export const fillCircle = (x: number, y: number, r: number, color: number) => {
const left = Math.floor(x-r-1);
const top = Math.floor(y-r-1);
for (let i = left; i <= Math.ceil(x+r+1); i ++) {
for (let j = top; j <= Math.ceil(y+r+1); j ++) {
if (Math.sqrt((x-i)**2 + (y-j)**2) <= r+0.5) {
setPixelColor(i, j, color);
}
}
}
}
export const outlineCircle = (x: number, y: number, r: number, color: number) => {
const left = Math.floor(x-r-1);
const top = Math.floor(y-r-1);
const inR = (d: number) => d <= r+0.5 && d > r-0.5;
for (let i = left; i <= Math.ceil(x+r+1); i ++) {
for (let j = top; j <= Math.ceil(y+r+1); j ++) {
const d = Math.sqrt((x-i)**2 + (y-j)**2);
if (inR(d)) {
const dh = Math.sqrt((x-(i+Math.sign(i-x)))**2 + (y-j)**2);
const dv = Math.sqrt((x-i)**2 + (y-(j+Math.sign(j-y)))**2);
const h = Math.abs(x-i) > Math.abs(y-j);
if (!inR(h ? dh : dv)) {
setPixelColor(i, j, color);
}
}
}
}
}
export const fillEllipse = (x0: number, y0: number, x1: number, y1: number, color: number) => {
const x = 0.5*(x0 + x1);
const y = 0.5*(y0 + y1);
const rx = Math.abs(x0-x1)/2;
const ry = Math.abs(y0-y1)/2;
const left = Math.floor(x-rx-1);
const top = Math.floor(y-ry-1);
for (let i = left; i <= Math.ceil(x+rx+1); i ++) {
for (let j = top; j <= Math.ceil(y+ry+1); j ++) {
if (Math.sqrt(((x-i)/rx)**2 + ((y-j)/ry)**2) <= 1+(1/(rx+ry))) {
setPixelColor(i, j, color);
}
}
}
}
export const outlineEllipse = (x0: number, y0: number, x1: number, y1: number, color: number) => {
const x = 0.5*(x0 + x1);
const y = 0.5*(y0 + y1);
const rx = Math.abs(x0-x1)/2;
const ry = Math.abs(y0-y1)/2;
const left = Math.floor(x-rx-1);
const top = Math.floor(y-ry-1);
const inR = (d: number) => d <= 1+1/(rx+ry);
for (let i = left; i <= Math.ceil(x+rx+1); i ++) {
for (let j = top; j <= Math.ceil(y+ry+1); j ++) {
const d = Math.sqrt(((x-i)/rx)**2 + ((y-j)/ry)**2);
if (inR(d)) {
const dh = Math.sqrt(((x-(i+Math.sign(i-x)))/rx)**2 + ((y-j)/ry)**2);
const dv = Math.sqrt(((x-i)/rx)**2 + ((y-(j+Math.sign(j-y)))/ry)**2);
if (!inR(dh) || !inR(dv)) {
setPixelColor(i, j, color);
}
}
}
}
}
export const fillRectRaw = (x: number, y: number, w: number, h: number, color: number) => {
setPixelsInRectRaw(x, y, w, Array(w*h).fill(color));
}
export const clearScreen = (color?: number) => {
fillRectRaw(0, 0, 128, 128, color ?? COLOR.BLACK);
}
export const frame = () => {
gl.Clear(gl.COLOR_BUFFER_BIT);
gl.UseProgram(program);
gl.VertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 0, allPixelTriangles);
gl.VertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 0, allPixelColors);
gl.EnableVertexAttribArray(0);
gl.EnableVertexAttribArray(1);
gl.DrawArrays(gl.TRIANGLES, 0, 6*pixelsPerRow*pixelsPerRow);
gameWindow.swapBuffers();
}

54
lang2/lexer.ts Normal file
View File

@ -0,0 +1,54 @@
type Token<T extends string> = {
type: T,
string: string,
}
type LexerProps<T extends string> = {
rules: {
[key in T]: RegExp;
},
// postprocess?: (token: Token<T>) =>
}
const entries = <K extends string, V>(obj: {[key in K]: V}) => {
return Object.entries(obj) as Array<[K, V]>;
}
const lexer = <T extends string>(props: LexerProps<T>) => {
const {rules} = props;
return (string: string): Array<Token<T>> => {
const tokens: Array<Token<T>> = [];
let str = string;
while (str.length) {
let matched = false;
for (const [type, matcher] of entries(rules)) {
const match = str.match(matcher);
if (match && match.index === 0) {
if (type !== "_skip") {
tokens.push({type, string: match[0]});
}
str = str.slice(match[0].length);
matched = true;
break;
}
}
if (!matched) {
console.log(tokens);
console.log(str);
throw 'Infinite Loop';
}
}
return tokens;
}
}
const my_lexer = lexer({
rules: {
symbol: /\w+/,
punctuation: /[\.,:;()[\]{}]/,
string_literal: /"([^"\\]|\\.)*"/,
_skip: /\s+/,
}
});
console.log(my_lexer(`abc def { ghi } "string literal!" "with \\"escaped\\" quote marks"`));

28
lang2/peg.js Normal file
View File

@ -0,0 +1,28 @@
const Expression = rule(
[{head: Term}, {tail: star([_, slash("+", "-"), _, Term])}],
({head, tail}) => {
return tail.reduce(function(result, element) {
if (element[1] === "+") { return result + element[3]; }
if (element[1] === "-") { return result - element[3]; }
}, head);
}
);
const Term = rule(
[{head: Factor}, {tail: star([_, slash("*", "/"), _, Factor])}],
({head, tail}) => {
return tail.reduce(function(result, element) {
if (element[1] === "*") { return result * element[3]; }
if (element[1] === "/") { return result / element[3]; }
}, head);
}
);
const Factor = slash(
rule(["(", _, {expr: Expression}, _, ")"], ({expr}) => expr),
Integer
);
const Integer = rule([_, /[0-9]+/], () => { return parseInt(text(), 10); });
const _ = /[ \t\n\r]*/;

View File

@ -1,130 +0,0 @@
import { drawText} from "../runtime/builtins.ts";
import { getKeysPressed, shiftKeyDown, shiftMap, K } from "../io/keyboard.ts";
import { font } from "../data/font.ts";
import { addToContext, evalCode } from "../runtime/runcode.ts";
import { clearScreen, fillRect } from "../io/window.ts";
import { COLOR } from "../data/colors.ts";
const lineHeight = 6;
const history: Array<string> = [];
let historyIndex = history.length;
let textLinesAbove: Array<string> = [];
let maxLineLen = 0;
let currentLine = "";
let index = 0;
export const resetRepl = () => {
historyIndex = history.length;
textLinesAbove.length = 0;
maxLineLen = 0;
currentLine = "";
index = 0;
}
const print = (arg: unknown) => {
textLinesAbove.push(...String(arg).split("\n").flatMap((line)=>{
const wrap = [];
while (line.length) {
wrap.push(line.slice(0,32));
line = line.slice(32);
}
return wrap;
}));
textLinesAbove = textLinesAbove.slice(-20);
}
const printVal = (arg: unknown) => {
print(JSON.stringify(arg));
}
addToContext("print", print);
addToContext("printVal", printVal);
const update = () => {
// TODO: model this after the newer editmode.ts version using getKeyboardString
for (const key of getKeysPressed()) {
let char = String.fromCharCode(key).toLowerCase();
if (shiftKeyDown()) {
if (char in shiftMap) {
char = shiftMap[char as keyof typeof shiftMap];
} else {
char = char.toUpperCase();
}
}
if (char in font.chars) {
currentLine = currentLine.slice(0, index)+char+currentLine.slice(index);
index += 1;
} else if (key === K.BACKSPACE) {
if (index > 0) {
currentLine = currentLine.slice(0, index-1)+currentLine.slice(index);
index -= 1;
}
} else if (key === K.ARROW_LEFT) {
index -= 1;
if (index < 0) {
index = 0;
}
} else if (key === K.ARROW_RIGHT) {
index += 1;
if (index > currentLine.length) {
index = currentLine.length;
}
} else if (key === K.ARROW_UP) {
historyIndex -= 1;
if (historyIndex < 0) {
historyIndex = -1;
}
const lineAtHistory = history[historyIndex] ?? "";
currentLine = lineAtHistory;
index = currentLine.length;
} else if (key === K.ARROW_DOWN) {
historyIndex += 1;
if (historyIndex > history.length) {
historyIndex = history.length;
}
const lineAtHistory = history[historyIndex] ?? "";
currentLine = lineAtHistory;
index = currentLine.length;
} else if (key === K.ENTER) {
if (currentLine) {
history.push(currentLine);
historyIndex = history.length;
}
print("> "+currentLine);
try {
const ran = evalCode(currentLine);
if (ran !== undefined) {
printVal(ran);
}
} catch (err) {
print(err.name+":\n"+err.message);
}
maxLineLen = 0;
currentLine = "";
index = 0;
}
}
maxLineLen = Math.max(maxLineLen, currentLine.length);
}
const drawTextAbove = () => {
textLinesAbove.forEach((line, i) => {
fillRect(0, 1+i*lineHeight, 4*(line.length+1)+1, lineHeight+1, COLOR.BLACK);
drawText(0, 1+i*lineHeight, line);
});
}
const draw = () => {
clearScreen();
drawTextAbove();
fillRect(0, 1+textLinesAbove.length*lineHeight, 4*(2+maxLineLen+1)+1, lineHeight+1, COLOR.BLACK);
fillRect((2+index)*4, textLinesAbove.length*lineHeight+1, 4, lineHeight-1, COLOR.RED);
drawText(0, 1+textLinesAbove.length*lineHeight, "> "+currentLine);
}
export const repl = {
update, draw
}

View File

@ -1,198 +0,0 @@
import {
setPixelsInRect,
clearScreen,
fillRect,
cameraPos,
fillCircle,
outlineCircle,
fillEllipse,
outlineEllipse,
setPixelColor,
} from "../io/window.ts";
import { CHAR, Font, font } from "../data/font.ts";
import { K, keyDown, keyPressed, keyReleased } from "../io/keyboard.ts";
import { addToContext, runCode } from "./runcode.ts";
import { resetRepl } from "../repl/repl.ts";
import { COLOR } from "../data/colors.ts";
import { getSheet, getCodeSheet, getMapSheet } from "../io/sheet.ts";
import { saveCart, loadCart } from "../io/cart.ts";
import { outlineRect } from "../util/util.ts";
let spritesheet: number | null = null;
export const getSpritesheet = () => {
return spritesheet;
}
export const useSpritesheet = (sheet: number) => {
spritesheet = sheet;
}
export const drawSprite = (x: number, y: number, spr: number) => {
if (!spritesheet) {
return;
}
const {sheet_type, value: sprites} = getSheet(spritesheet);
if (sheet_type !== "spritesheet") {
throw "Trying to run a non-code sheet as code."
}
setPixelsInRect(x, y, 8, sprites[spr]);
}
export const drawIcon = (x: number, y: number, icon: Array<number>, color: number) => {
setPixelsInRect(x, y, 8, icon.map(n => n*color));
}
export const measureCharFont = (char: string, fnt: Font) => {
return (fnt.chars[char]?.length ?? 0)/fnt.height;
}
export const drawCharFont = (x: number, y: number, char: string, fnt: Font, color: number) => {
const w = measureCharFont(char, fnt);
if (!fnt.chars[char]) {
return 0;
}
setPixelsInRect(x, y, w, fnt.chars[char].map(n => n*color));
return w;
}
export const drawTextFont = (x: number, y: number, text: string, fnt: Font, color?: number) => {
let dx = 0;
[...text].forEach((char) => {
dx += 1+drawCharFont(x+dx, y, char, fnt, color ?? COLOR.WHITE);
});
return dx-1;
}
export const measureTextFont = (text: string, fnt: Font) => {
let w = 0;
[...text].forEach((char) => {
w += measureCharFont(char, fnt)+1;
});
return Math.max(0, w-1);
}
export const drawText = (x: number, y: number, text: string, color?: number) => {
return drawTextFont(x, y, text, font, color);
}
export const measureText = (text: string) => {
return measureTextFont(text, font);
}
export const camera = (x: number, y: number) => {
cameraPos.x = x;
cameraPos.y = y;
};
const faux = {
// Graphics
cls: () => {
resetRepl();
clearScreen();
},
camera,
sprsht: useSpritesheet,
spr: drawSprite,
txt: drawText,
rectfill: fillRect,
rect: outlineRect,
circfill: fillCircle,
circ: outlineCircle,
ovalfill: fillEllipse,
oval: outlineEllipse,
pset: setPixelColor,
map: (mapSheet: number, tileX: number, tileY: number, screenX: number, screenY: number, tileW: number, tileH: number) => {
const originalSpritesheet = getSpritesheet() ?? 0;
getMapSheet(mapSheet).values.forEach(([sprSheet, spr], i) => {
const x = i%64;
const y = Math.floor(i/64);
if (x >= tileX && y >= tileY && x < tileX + tileW && y < tileY + tileH) {
useSpritesheet(sprSheet);
drawSprite(screenX + (x-tileX)*8, screenY + (y-tileY)*8, spr);
}
});
useSpritesheet(originalSpritesheet);
},
// Map
mgetsht: (mapSheet: number, x: number, y: number) => {
if (x < 0 || x >= 64 || y < 0 || y >= 64) {
return undefined;
}
return getMapSheet(mapSheet).get(x, y)[0];
},
mgetspr: (mapSheet: number, x: number, y: number) => {
if (x < 0 || x >= 64 || y < 0 || y >= 64) {
return undefined;
}
return getMapSheet(mapSheet).get(x, y)[1];
},
// Temporarily removing mset, since it would overwrite static cart data
// mset: (mapSheet: number, x: number, y: number, sprSheet: number, spr: number) => {
// if (x < 0 || x >= 64 || y < 0 || y >= 64) {
// return;
// }
// getMapSheet(mapSheet).set(x, y, [sprSheet, spr]);
// },
// Input
[CHAR.UP]: K.ARROW_UP,
[CHAR.DOWN]: K.ARROW_DOWN,
[CHAR.LEFT]: K.ARROW_LEFT,
[CHAR.RIGHT]: K.ARROW_RIGHT,
btn: keyDown,
btnp: keyPressed,
btnr: keyReleased,
// Cart
save: saveCart,
load: loadCart,
// JS
Array,
BigInt: BigInt,
Boolean,
Date,
Error,
Function,
Infinity: Infinity,
JSON: JSON,
Map,
NaN: NaN,
Number,
Object,
Promise,
Proxy,
Reflect: Reflect,
RegExp,
Set,
String,
Symbol: Symbol,
WeakMap,
WeakRef,
WeakSet,
isFinite,
isNaN,
parseFloat,
parseInt,
// Math
max: Math.max,
min: Math.min,
floor: Math.floor,
ceil: Math.ceil,
sin: Math.sin,
cos: Math.cos,
atan2: Math.atan2,
sqrt: Math.sqrt,
abs: Math.abs,
rand: Math.random,
[CHAR.PI]: Math.PI,
// Other
code: (n: number) => {
return runCode(getCodeSheet(n));
},
log: console.log,
};
for (const key in faux) {
addToContext(key, faux[key as keyof typeof faux]);
}
export default faux;

View File

@ -1,61 +0,0 @@
// deno-lint-ignore no-explicit-any
const builtins: any = {};
// deno-lint-ignore no-explicit-any
const G: any = {};
// deno-lint-ignore no-explicit-any
export const addToContext = (name: string, value: any) => {
builtins[name] = value;
}
export const getBuiltins = () => {
return builtins;
}
// deno-lint-ignore no-explicit-any
const AsyncFunction = (async function () {}).constructor as any;
addToContext("eval", eval);
const context = new Proxy(G, {
get: (target, prop) => {
if (prop in builtins) {
return builtins[prop as keyof typeof builtins];
}
return target[prop];
},
set: (target, prop, value) => {
target[prop] = value;
return true;
},
has: () => {
return true;
},
});
export const runCode = async (code: string) => {
try {
new AsyncFunction(code);
} catch (err) {
throw err;
}
const fn = new AsyncFunction("context", `
with (context) {
${code}
}
`);
return await fn(context);
}
export const evalCode = (code: string) => {
try {
return runCode(`return eval("(${code.replaceAll('"', '\\"')})");`);
} catch (err) {
if (err.name === "SyntaxError") {
return runCode(`return eval("${code.replaceAll('"', '\\"')}");`);
} else {
throw err;
}
}
}

View File

@ -1,98 +0,0 @@
import { COLOR } from "../data/colors.ts";
import { fillRect, setPixelColor } from "../io/window.ts";
export const inRect = (x: number, y: number, rectX: number, rectY: number, rectW: number, rectH: number) => {
return (
x >= rectX &&
x < rectX+rectW &&
y >= rectY &&
y < rectY+rectH
)
}
export function reGridWithGap (x: number, y: number, gridX: number, gridY: number, cellW: number, cellH: number, gapX: number, gapY: number): {x: number, y: number} | null {
const gx = Math.floor((x-gridX)/(cellW+gapX));
const gy = Math.floor((y-gridY)/(cellH+gapY));
if (x >= gridX+(cellW+gapX)*gx+cellW || y >= gridY+(cellH+gapY)*gy+cellH) {
return null;
}
return {
x: Math.floor((x-gridX)/(cellW+gapX)),
y: Math.floor((y-gridY)/(cellH+gapY)),
}
}
export function reGrid (x: number, y: number, gridX: number, gridY: number, cellW: number, cellH: number): {x: number, y: number} {
const gx = Math.floor((x-gridX)/(cellW));
const gy = Math.floor((y-gridY)/(cellH));
return {
x: gx,
y: gy,
}
}
export const outlineRect = (x: number, y: number, w: number, h: number, color: number) => {
fillRect(x, y, w, 1, color);
fillRect(x, y, 1, h, color);
fillRect(x+w-1, y, 1, h, color);
fillRect(x, y+h-1, w, 1, color);
}
export const drawTransparentRect = (x: number, y: number, w: number, h: number) => {
Array(w*h).fill(0).map((_z, j) => {
const jx = j%w;
const jy = Math.floor(j/w);
setPixelColor(x+jx, y+jy, (jx+jy)%2 ? COLOR.BLACK : COLOR.DARKGRAY);
})
}
export const drawVoidRect = (x: number, y: number, w: number, h: number) => {
Array(w*h).fill(0).map((_z, j) => {
const jx = j%w;
const jy = Math.floor(j/w);
setPixelColor(x+jx, y+jy, (jx+jy)%2 ? COLOR.BLACK : COLOR.DARKERBLUE);
})
}
export const subgrid = <T>(array: Array<T>, gridW: number, x: number, y: number, w: number, h: number): Array<T|undefined> => {
return Array(h).fill(0).flatMap((_, i) => {
if (y+i < 0 || y+i > array.length/gridW) {
return Array(w).fill(undefined);
}
const x0 = Math.max(0, x);
const x1 = Math.min(x+w, gridW);
const start = (y+i)*gridW+x0;
const end = (y+i)*gridW+x1;
const before = Array(x0 - x).fill(undefined);
const after = Array((x+w) - x1).fill(undefined);
const middle = array.slice(start, end);
return [...before, ...middle, ...after];
})
}
export const LinearGrid = <T>(array: Array<T>, gridW: number) => {
return {
get(x: number, y: number) {
return array[this.coordsToIndex(x, y)]
},
getIndex(i: number) {
return array[i];
},
set(x: number, y: number, value: T) {
array[this.coordsToIndex(x, y)] = value;
},
setIndex(i: number, value: T) {
array[i] = value;
},
values: array,
indexToCoords: (i: number) => {
return [i%gridW, Math.floor(i/gridW)];
},
coordsToIndex: (x: number, y: number) => {
return y*gridW+x;
},
// TODO: make alterations to subgrid affect parent grid
subgrid: (x: number, y: number, w: number, h: number) => LinearGrid(subgrid(array, gridW, x, y, w, h), w),
}
}