Add lunardash
This commit is contained in:
parent
5317e1a48e
commit
26be488d70
|
@ -1,5 +1,6 @@
|
||||||
# Typescript
|
# Typescript
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
| ------------------- | ----------------------------------------------------------------------------------------------------- |
|
| ------------------------- | ------------------------------------------------------------------------------------------------------- |
|
||||||
| [wave38](./wave38/) | Remake of [wave37](https://github.com/Mateiadrielrafael/wave37) I dropped super early in development. |
|
| [lunardash](./lunardash/) | Rhythm game I dropped super early into development |
|
||||||
|
| [wave38](./wave38/) | Remake of [wave37](https://github.com/Mateiadrielrafael/wave37) I dropped super early into development. |
|
||||||
|
|
4
typescript/lunardash/.gitignore
vendored
Normal file
4
typescript/lunardash/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.build
|
||||||
|
build
|
||||||
|
web_modules
|
||||||
|
node_modules
|
4
typescript/lunardash/.prettierrc
Normal file
4
typescript/lunardash/.prettierrc
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "all"
|
||||||
|
}
|
24
typescript/lunardash/README.md
Normal file
24
typescript/lunardash/README.md
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# New Project
|
||||||
|
|
||||||
|
> ✨ Bootstrapped with Create Snowpack App (CSA).
|
||||||
|
|
||||||
|
## Available Scripts
|
||||||
|
|
||||||
|
### npm start
|
||||||
|
|
||||||
|
Runs the app in the development mode.
|
||||||
|
Open http://localhost:8080 to view it in the browser.
|
||||||
|
|
||||||
|
The page will reload if you make edits.
|
||||||
|
You will also see any lint errors in the console.
|
||||||
|
|
||||||
|
### npm run build
|
||||||
|
|
||||||
|
Builds a static copy of your site to the `build/` folder.
|
||||||
|
Your app is ready to be deployed!
|
||||||
|
|
||||||
|
**For the best production performance:** Add a build bundler plugin like [@snowpack/plugin-webpack](https://github.com/snowpackjs/snowpack/tree/main/plugins/plugin-webpack) or [snowpack-plugin-rollup-bundle](https://github.com/ParamagicDev/snowpack-plugin-rollup-bundle) to your `snowpack.config.mjs` config file.
|
||||||
|
|
||||||
|
### Q: What about Eject?
|
||||||
|
|
||||||
|
No eject needed! Snowpack guarantees zero lock-in, and CSA strives for the same.
|
20
typescript/lunardash/package.json
Normal file
20
typescript/lunardash/package.json
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"start": "snowpack dev",
|
||||||
|
"build": "snowpack build",
|
||||||
|
"test": "echo \"This template does not include a test runner by default.\" && exit 1",
|
||||||
|
"format": "prettier --write \"src/**/*.{ts,js}\"",
|
||||||
|
"lint": "prettier --check \"src/**/*.{ts,js}\""
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"canvas-confetti": "^1.2.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@snowpack/plugin-typescript": "^1.2.1",
|
||||||
|
"@types/canvas-confetti": "^1.0.0",
|
||||||
|
"@types/snowpack-env": "^2.3.3",
|
||||||
|
"prettier": "^2.2.1",
|
||||||
|
"snowpack": "^3.3.7",
|
||||||
|
"typescript": "^4.2.4"
|
||||||
|
}
|
||||||
|
}
|
1463
typescript/lunardash/pnpm-lock.yaml
Normal file
1463
typescript/lunardash/pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load diff
BIN
typescript/lunardash/public/favicon.ico
Normal file
BIN
typescript/lunardash/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
11
typescript/lunardash/public/index.css
Normal file
11
typescript/lunardash/public/index.css
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
body,
|
||||||
|
html {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#canvas {
|
||||||
|
display: block;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
17
typescript/lunardash/public/index.html
Normal file
17
typescript/lunardash/public/index.html
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<meta name="description" content="Web site created using create-snowpack-app" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="/index.css" />
|
||||||
|
<title>Lunardash</title>
|
||||||
|
|
||||||
|
<script type="module" defer src="/dist/index.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas id="canvas"></canvas>
|
||||||
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
</body>
|
||||||
|
</html>
|
7
typescript/lunardash/public/logo.svg
Normal file
7
typescript/lunardash/public/logo.svg
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
|
<path fill="#E44D26" d="M107.6 470.9l-33-370.3h362.8l-33.1 370.2L255.8 512z"/>
|
||||||
|
<path fill="#F16529" d="M256 480.5l120-33.3 28.3-316.3H256z"/>
|
||||||
|
<path fill="#EBEBEB" d="M256 268.2h-60.1l-4.1-46.5H256v-45.4H142.1l1.1 12.2 11.2 125.1H256zM256 386.2h-.2l-50.6-13.6-3.2-36.3h-45.6l6.4 71.3 93 25.9.2-.1z"/>
|
||||||
|
<path d="M108.4 0h23v22.8h21.2V0h23v69h-23V46h-21.1v23h-23.1V0zM206 22.9h-20.3V0h63.7v22.9h-20.3V69H206V23zM259.5 0h24l14.9 24.3L313.2 0h24v69h-23V34.8l-15.8 24.6h-.4l-16-24.6V69h-22.5V0zM348.7 0h23.1v46.2h32.5V69h-55.6V0z"/>
|
||||||
|
<path fill="#FFF" d="M255.8 268.2v45.4h56l-5.3 58.9-50.7 13.7v47.2l93.1-25.8.7-7.6 10.7-119.6 1.1-12.2h-12.2zM255.8 176.3v45.4H365.5l.9-10.2 2.1-23 1.1-12.2z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 767 B |
3
typescript/lunardash/public/robots.txt
Normal file
3
typescript/lunardash/public/robots.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# https://www.robotstxt.org/robotstxt.html
|
||||||
|
User-agent: *
|
||||||
|
Disallow:
|
BIN
typescript/lunardash/public/songs/heracles.mp3
Normal file
BIN
typescript/lunardash/public/songs/heracles.mp3
Normal file
Binary file not shown.
33
typescript/lunardash/snowpack.config.mjs
Normal file
33
typescript/lunardash/snowpack.config.mjs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/** @type {import("snowpack").SnowpackUserConfig } */
|
||||||
|
export default {
|
||||||
|
mount: {
|
||||||
|
public: { url: '/', static: true },
|
||||||
|
src: { url: '/dist' },
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
[
|
||||||
|
'@snowpack/plugin-typescript',
|
||||||
|
{
|
||||||
|
/* Yarn PnP workaround: see https://www.npmjs.com/package/@snowpack/plugin-typescript */
|
||||||
|
...(process.versions.pnp ? { tsc: 'yarn pnpify tsc' } : {}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
routes: [
|
||||||
|
/* Enable an SPA Fallback in development: */
|
||||||
|
// {"match": "routes", "src": ".*", "dest": "/index.html"},
|
||||||
|
],
|
||||||
|
optimize: {
|
||||||
|
/* Example: Bundle your final build: */
|
||||||
|
// "bundle": true,
|
||||||
|
},
|
||||||
|
packageOptions: {
|
||||||
|
/* ... */
|
||||||
|
},
|
||||||
|
devOptions: {
|
||||||
|
/* ... */
|
||||||
|
},
|
||||||
|
buildOptions: {
|
||||||
|
/* ... */
|
||||||
|
},
|
||||||
|
};
|
17
typescript/lunardash/src/Chart.ts
Normal file
17
typescript/lunardash/src/Chart.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
export const enum Axis {
|
||||||
|
Negative = -1,
|
||||||
|
Zero = 0,
|
||||||
|
Positive = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Direction = [Axis, Axis];
|
||||||
|
|
||||||
|
export interface Note {
|
||||||
|
stamp: number;
|
||||||
|
orientation: Direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Chart {
|
||||||
|
path: Array<Note>;
|
||||||
|
song: HTMLAudioElement;
|
||||||
|
}
|
37
typescript/lunardash/src/State.ts
Normal file
37
typescript/lunardash/src/State.ts
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import type { Chart } from './Chart';
|
||||||
|
|
||||||
|
export const enum NoteJudgement {
|
||||||
|
Missed,
|
||||||
|
Far,
|
||||||
|
Perfect,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum NoteTiming {
|
||||||
|
Early,
|
||||||
|
Late,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NoteState {
|
||||||
|
judgement: NoteJudgement;
|
||||||
|
timing: NoteTiming;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface State {
|
||||||
|
song: HTMLAudioElement;
|
||||||
|
currentNote: number;
|
||||||
|
notes: NoteState[];
|
||||||
|
readonly chart: Chart;
|
||||||
|
readonly settings: Settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Settings {
|
||||||
|
offset: number;
|
||||||
|
judgments: {
|
||||||
|
perfect: number;
|
||||||
|
far: number;
|
||||||
|
};
|
||||||
|
scrollSpeed: number;
|
||||||
|
implicitScrollSpeed: number;
|
||||||
|
windowCenter: number;
|
||||||
|
noteSize: number;
|
||||||
|
}
|
176
typescript/lunardash/src/index.ts
Normal file
176
typescript/lunardash/src/index.ts
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
import type { Chart, Note } from './Chart';
|
||||||
|
import { NoteJudgement, NoteTiming, State } from './State';
|
||||||
|
|
||||||
|
const canvas = document.getElementById('canvas')! as HTMLCanvasElement;
|
||||||
|
const ctx = canvas.getContext('2d')!;
|
||||||
|
|
||||||
|
const song = new Audio('/songs/heracles.mp3');
|
||||||
|
|
||||||
|
const heracles: Chart = {
|
||||||
|
song,
|
||||||
|
path: [
|
||||||
|
{
|
||||||
|
stamp: 1.906999,
|
||||||
|
orientation: [0, 1],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stamp: 3.115963,
|
||||||
|
orientation: [0, 1],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stamp: 4.365792,
|
||||||
|
orientation: [0, 1],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stamp: 5.645609,
|
||||||
|
orientation: [0, 1],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stamp: 6.894808,
|
||||||
|
orientation: [0, 1],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stamp: 8.099023,
|
||||||
|
orientation: [0, 1],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stamp: 9.337156,
|
||||||
|
orientation: [0, 1],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
let started = false;
|
||||||
|
|
||||||
|
const state: State = {
|
||||||
|
chart: heracles,
|
||||||
|
currentNote: 0,
|
||||||
|
notes: [],
|
||||||
|
song,
|
||||||
|
settings: {
|
||||||
|
offset: 0.05,
|
||||||
|
judgments: {
|
||||||
|
far: 0.1,
|
||||||
|
perfect: 0.042,
|
||||||
|
},
|
||||||
|
scrollSpeed: 4,
|
||||||
|
implicitScrollSpeed: 100,
|
||||||
|
windowCenter: 100,
|
||||||
|
noteSize: 10,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const start = () => {
|
||||||
|
started = true;
|
||||||
|
|
||||||
|
state.song.play();
|
||||||
|
|
||||||
|
main();
|
||||||
|
resize();
|
||||||
|
};
|
||||||
|
|
||||||
|
const resize = () => {
|
||||||
|
canvas.width = window.innerWidth;
|
||||||
|
canvas.height = window.innerHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
const main = () => {
|
||||||
|
if (state.song.currentTime > state.chart.path[state.currentNote].stamp) {
|
||||||
|
state.currentNote++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const time = state.song.currentTime - state.settings.offset;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const firstNote = state.chart.path[state.notes.length];
|
||||||
|
const delta = time - firstNote.stamp;
|
||||||
|
|
||||||
|
if (delta > state.settings.judgments.far) {
|
||||||
|
state.notes.push({
|
||||||
|
timing: NoteTiming.Late,
|
||||||
|
judgement: NoteJudgement.Missed,
|
||||||
|
});
|
||||||
|
} else break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.clearRect(0, 0, 3000, 3000);
|
||||||
|
|
||||||
|
ctx.fillStyle = 'rgba(0,0,0,0.3)';
|
||||||
|
ctx.fillRect(0, 200, window.innerWidth, 100);
|
||||||
|
|
||||||
|
ctx.fillStyle = 'blue';
|
||||||
|
ctx.fillRect(
|
||||||
|
state.settings.windowCenter - state.settings.noteSize / 2,
|
||||||
|
200,
|
||||||
|
state.settings.noteSize,
|
||||||
|
100,
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.fillStyle = 'rgba(0,0,256,0.3)';
|
||||||
|
const farSize =
|
||||||
|
state.settings.judgments.far *
|
||||||
|
state.settings.scrollSpeed *
|
||||||
|
state.settings.implicitScrollSpeed;
|
||||||
|
|
||||||
|
ctx.fillRect(state.settings.windowCenter - farSize, 200, farSize * 2, 100);
|
||||||
|
|
||||||
|
for (let index = 0; index < heracles.path.length; index++) {
|
||||||
|
const note = heracles.path[index];
|
||||||
|
if (state.notes[index]?.judgement === NoteJudgement.Missed)
|
||||||
|
ctx.fillStyle = 'red';
|
||||||
|
else if (state.notes[index]?.judgement === NoteJudgement.Far)
|
||||||
|
ctx.fillStyle =
|
||||||
|
state.notes[index].timing === NoteTiming.Late ? 'orange' : 'blue';
|
||||||
|
else if (state.notes[index]?.judgement === NoteJudgement.Perfect)
|
||||||
|
ctx.fillStyle = 'green';
|
||||||
|
else ctx.fillStyle = 'yellow';
|
||||||
|
|
||||||
|
ctx.fillRect(
|
||||||
|
state.settings.windowCenter +
|
||||||
|
(note.stamp - song.currentTime) *
|
||||||
|
state.settings.scrollSpeed *
|
||||||
|
state.settings.implicitScrollSpeed,
|
||||||
|
200,
|
||||||
|
state.settings.noteSize,
|
||||||
|
100,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(main);
|
||||||
|
};
|
||||||
|
|
||||||
|
canvas.onclick = () => {
|
||||||
|
if (!started) return start();
|
||||||
|
|
||||||
|
const time = state.song.currentTime - state.settings.offset;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const firstNote = state.chart.path[state.notes.length];
|
||||||
|
|
||||||
|
if (!firstNote) return;
|
||||||
|
|
||||||
|
const delta = time - firstNote.stamp;
|
||||||
|
const absoluteDelta = Math.abs(delta);
|
||||||
|
const timing = delta < 0 ? NoteTiming.Early : NoteTiming.Late;
|
||||||
|
|
||||||
|
console.log({ timing, delta, firstNote, absoluteDelta, time });
|
||||||
|
|
||||||
|
if (delta > state.settings.judgments.far) {
|
||||||
|
state.notes.push({
|
||||||
|
timing: NoteTiming.Late,
|
||||||
|
judgement: NoteJudgement.Missed,
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
} else if (absoluteDelta > state.settings.judgments.far) return;
|
||||||
|
else
|
||||||
|
state.notes.push({
|
||||||
|
timing,
|
||||||
|
judgement:
|
||||||
|
absoluteDelta < state.settings.judgments.perfect
|
||||||
|
? NoteJudgement.Perfect
|
||||||
|
: NoteJudgement.Far,
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
29
typescript/lunardash/tsconfig.json
Normal file
29
typescript/lunardash/tsconfig.json
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"include": ["src", "types"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "esnext",
|
||||||
|
"target": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"jsx": "preserve",
|
||||||
|
"baseUrl": "./",
|
||||||
|
/* paths - import rewriting/resolving */
|
||||||
|
"paths": {
|
||||||
|
// If you configured any Snowpack aliases, add them here.
|
||||||
|
// Add this line to get types for streaming imports (packageOptions.source="remote"):
|
||||||
|
// "*": [".snowpack/types/*"]
|
||||||
|
// More info: https://www.snowpack.dev/guides/streaming-imports
|
||||||
|
},
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"importsNotUsedAsValues": "error",
|
||||||
|
/* more strict checking for errors that per-file transpilers like `esbuild` would crash */
|
||||||
|
"isolatedModules": true,
|
||||||
|
/* noEmit - We only use TypeScript for type checking. */
|
||||||
|
"noEmit": true,
|
||||||
|
/* Additional Options */
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"useDefineForClassFields": true
|
||||||
|
}
|
||||||
|
}
|
59
typescript/lunardash/types/static.d.ts
vendored
Normal file
59
typescript/lunardash/types/static.d.ts
vendored
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/* Use this file to declare any custom file extensions for importing */
|
||||||
|
/* Use this folder to also add/extend a package d.ts file, if needed. */
|
||||||
|
|
||||||
|
/* CSS MODULES */
|
||||||
|
declare module '*.module.css' {
|
||||||
|
const classes: { [key: string]: string };
|
||||||
|
export default classes;
|
||||||
|
}
|
||||||
|
declare module '*.module.scss' {
|
||||||
|
const classes: { [key: string]: string };
|
||||||
|
export default classes;
|
||||||
|
}
|
||||||
|
declare module '*.module.sass' {
|
||||||
|
const classes: { [key: string]: string };
|
||||||
|
export default classes;
|
||||||
|
}
|
||||||
|
declare module '*.module.less' {
|
||||||
|
const classes: { [key: string]: string };
|
||||||
|
export default classes;
|
||||||
|
}
|
||||||
|
declare module '*.module.styl' {
|
||||||
|
const classes: { [key: string]: string };
|
||||||
|
export default classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CSS */
|
||||||
|
declare module '*.css';
|
||||||
|
declare module '*.scss';
|
||||||
|
declare module '*.sass';
|
||||||
|
declare module '*.less';
|
||||||
|
declare module '*.styl';
|
||||||
|
|
||||||
|
/* IMAGES */
|
||||||
|
declare module '*.svg' {
|
||||||
|
const ref: string;
|
||||||
|
export default ref;
|
||||||
|
}
|
||||||
|
declare module '*.bmp' {
|
||||||
|
const ref: string;
|
||||||
|
export default ref;
|
||||||
|
}
|
||||||
|
declare module '*.gif' {
|
||||||
|
const ref: string;
|
||||||
|
export default ref;
|
||||||
|
}
|
||||||
|
declare module '*.jpg' {
|
||||||
|
const ref: string;
|
||||||
|
export default ref;
|
||||||
|
}
|
||||||
|
declare module '*.jpeg' {
|
||||||
|
const ref: string;
|
||||||
|
export default ref;
|
||||||
|
}
|
||||||
|
declare module '*.png' {
|
||||||
|
const ref: string;
|
||||||
|
export default ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CUSTOM: ADD YOUR OWN HERE */
|
Loading…
Reference in a new issue