Compare commits
55 Commits
eb7e98b384
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef162a7dc2 | ||
|
|
26ad150b59 | ||
|
|
9bb7ec99c0 | ||
|
|
db2110c921 | ||
|
|
b3dbc9cc80 | ||
|
|
ef2ea386c5 | ||
|
|
fa477afb9a | ||
|
|
28ef7b9c6f | ||
|
|
a8be84ebd3 | ||
|
|
27f3d2e916 | ||
|
|
9fea67dbcc | ||
|
|
add005d963 | ||
|
|
681ba1b632 | ||
|
|
272a86d7fc | ||
|
|
70c19f2851 | ||
|
|
c9c063b477 | ||
|
|
27862e19df | ||
|
|
70130f47a4 | ||
|
|
33310100f7 | ||
|
|
71b2afacc4 | ||
|
|
007d2568b3 | ||
|
|
7214a64b77 | ||
|
|
f2e62a7e74 | ||
|
|
c01ac53312 | ||
|
|
1124e62bb7 | ||
|
|
b591fc2dee | ||
|
|
e44355bf21 | ||
|
|
39da3d8abd | ||
|
|
a52754ce0d | ||
|
|
59f1a4b164 | ||
|
|
e714fc35f6 | ||
|
|
8ecfbf499f | ||
|
|
85c83a8827 | ||
|
|
dff1a6a760 | ||
|
|
e99b8b6bf8 | ||
|
|
e91368d380 | ||
|
|
dbf34061f0 | ||
|
|
7b8745d7d2 | ||
|
|
66ef2eaa31 | ||
|
|
07b64154e1 | ||
|
|
603bf3addc | ||
|
|
8ca64a19b7 | ||
|
|
71f48404c9 | ||
|
|
c8767f1119 | ||
|
|
18c323430c | ||
|
|
e75946d749 | ||
|
|
cffb10aed6 | ||
|
|
9b5ab25c4d | ||
|
|
8a6e3b86df | ||
|
|
8c86e89470 | ||
|
|
7337a4c917 | ||
|
|
8ef5e61588 | ||
|
|
c8cd522c94 | ||
|
|
fd799ea724 | ||
|
|
0de74e11a3 |
44
.github/workflows/build.yml
vendored
@@ -29,29 +29,65 @@ jobs:
|
||||
with:
|
||||
node-version: 21
|
||||
- name: Orbits Install dependencies
|
||||
run: npm install
|
||||
run: npm ci
|
||||
working-directory: orbits
|
||||
- name: Orbits Build
|
||||
run: npx vite build
|
||||
working-directory: orbits
|
||||
- name: recBubbles Install dependencies
|
||||
run: npm install
|
||||
run: npm ci
|
||||
working-directory: recBubbles
|
||||
- name: recBubbles Build
|
||||
run: npx vite build
|
||||
working-directory: recBubbles
|
||||
- name: balls Install dependencies
|
||||
run: npm install
|
||||
run: npm ci
|
||||
working-directory: balls
|
||||
- name: balls Build
|
||||
run: npx vite build
|
||||
working-directory: balls
|
||||
- name: fireWorks Install dependencies
|
||||
run: npm install
|
||||
run: npm ci
|
||||
working-directory: fireWorks
|
||||
- name: fireWorks Build
|
||||
run: npx vite build
|
||||
working-directory: fireWorks
|
||||
- name: bubbles Install dependencies
|
||||
run: npm ci
|
||||
working-directory: bubbles
|
||||
- name: bubbles Build
|
||||
run: npx vite build
|
||||
working-directory: bubbles
|
||||
- name: circleBs Install dependencies
|
||||
run: npm ci
|
||||
working-directory: circleBs
|
||||
- name: circleBs Build
|
||||
run: npx vite build
|
||||
working-directory: circleBs
|
||||
- name: clusterFilter Install dependencies
|
||||
run: npm ci
|
||||
working-directory: clusterFilter
|
||||
- name: clusterFilter Build
|
||||
run: npx vite build
|
||||
working-directory: clusterFilter
|
||||
- name: collatzConjecture Install dependencies
|
||||
run: npm ci
|
||||
working-directory: collatzConjecture
|
||||
- name: collatzConjecture Build
|
||||
run: npx vite build
|
||||
working-directory: collatzConjecture
|
||||
- name: dotLines Install dependencies
|
||||
run: npm ci
|
||||
working-directory: dotLines
|
||||
- name: dotLines Build
|
||||
run: npx vite build
|
||||
working-directory: dotLines
|
||||
- name: survivors install dependencies
|
||||
run: npm ci
|
||||
working-directory: absurd-survivors
|
||||
- name: survivors build
|
||||
run: npx vite build
|
||||
working-directory: absurd-survivors
|
||||
- name: Move index
|
||||
run: cp index.html dist/
|
||||
- name: Move overview images
|
||||
|
||||
24
absurd-survivors/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
13
absurd-survivors/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html class="no-js" lang="">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>overtuned survivors</title>
|
||||
<meta name="description" content="">
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="canvas" style="display: block; background-color: black"></canvas>
|
||||
<script type="module" src="src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
1088
absurd-survivors/package-lock.json
generated
Normal file
16
absurd-survivors/package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "overtuned-survivors",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"canvas-common": "file:../canvas-common",
|
||||
"typescript": "~5.8.3",
|
||||
"vite": "^7.1.2"
|
||||
}
|
||||
}
|
||||
321
absurd-survivors/src/Enemies.ts
Normal file
@@ -0,0 +1,321 @@
|
||||
import type {Acting, ChanceEntry, Drawable, Healthy, Placeable, Shooting} from "./interfaces.ts";
|
||||
import {fillDot, moveInDirectionOf} from "./utils.ts";
|
||||
import {Vector} from "./base.ts";
|
||||
import {World} from "./World.ts";
|
||||
import type {Projectile} from "./projectile.ts";
|
||||
import {StraightProjectile} from "./projectile.ts";
|
||||
import {HealthPack, ItemDrop, LevelDrop, MoneyDrop} from "./drop.ts";
|
||||
import {ItemManagement} from "./items.ts";
|
||||
import {EnemyStats, ProjectileStats} from "./stats.ts";
|
||||
import {EnemyStatus} from "./status.ts";
|
||||
import {NumberDisplayParticle} from "./particles.ts";
|
||||
|
||||
export abstract class Enemy implements Placeable, Drawable, Acting, Healthy {
|
||||
protected _position: Vector;
|
||||
protected speed: number;
|
||||
protected world: World;
|
||||
protected size: number
|
||||
protected status: EnemyStatus;
|
||||
protected drops: KillChanceTable;
|
||||
|
||||
constructor(position: Vector, enemyStats: EnemyStats) {
|
||||
this.drops = new KillChanceTable();
|
||||
this.drops.addDrop( {chance: 10, creationMethod: this.spawnMoney})
|
||||
this._position = position.clone();
|
||||
let health = enemyStats.getEffectiveHealth()
|
||||
this.status = new EnemyStatus(health);
|
||||
}
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
}
|
||||
|
||||
act() {
|
||||
this.move()
|
||||
}
|
||||
|
||||
move() {
|
||||
}
|
||||
|
||||
|
||||
getPosition(): Vector {
|
||||
return this._position;
|
||||
}
|
||||
|
||||
takeDamage(damage: number) {
|
||||
this.status.health -= damage;
|
||||
NumberDisplayParticle.spawnNumberParticle(this.world, damage, this._position, 'white')
|
||||
if(this.status.dead) {
|
||||
this.die()
|
||||
this.world.removeEnemy(this)
|
||||
}
|
||||
}
|
||||
|
||||
die() {
|
||||
let draw = this.drops.draw();
|
||||
if(draw) {
|
||||
draw.creationMethod(this)
|
||||
}
|
||||
}
|
||||
|
||||
spawnMoney(enemy: Enemy) {
|
||||
MoneyDrop.spawnMoneyDrop(enemy.world, enemy._position);
|
||||
}
|
||||
|
||||
getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
dead() {
|
||||
return this.status.dead
|
||||
}
|
||||
|
||||
tick(seconds: number, tick: number) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class BasicEnemy extends Enemy {
|
||||
|
||||
constructor(position: Vector, enemyStats: EnemyStats) {
|
||||
super(position, enemyStats);
|
||||
}
|
||||
|
||||
protected color: string;
|
||||
protected impactDamage: number;
|
||||
protected impactCooldown: number = 0;
|
||||
protected impactInterval: number = 60;
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
fillDot(this._position, this.getSize(), this.color, ctx)
|
||||
}
|
||||
|
||||
|
||||
move() {
|
||||
this._position = moveInDirectionOf(this._position, this.world.player.position, this.speed)
|
||||
}
|
||||
|
||||
act() {
|
||||
super.act();
|
||||
if(this._position.distanceTo(this.world.player.position) < this.getSize() && this.impactCooldown <= 0) {
|
||||
this.world.player.takeDamage(this.impactDamage)
|
||||
this.impactCooldown = this.impactInterval;
|
||||
}
|
||||
this.impactCooldown -= 1;
|
||||
}
|
||||
|
||||
static spawnBasicEnemy(world: World, position?: Vector) {
|
||||
world.addEnemy(this.generateBasicEnemy(world, position))
|
||||
}
|
||||
|
||||
static generateBasicEnemy(world: World, position?: Vector): BasicEnemy {
|
||||
if(position === undefined) {
|
||||
position = world.randomPlace()
|
||||
}
|
||||
let enemyStats = new EnemyStats().withHealthFactor(world.getEnemyHealthFactor());
|
||||
let basicEnemy = new BasicEnemy(position, enemyStats);
|
||||
basicEnemy.size = 5;
|
||||
basicEnemy.world = world;
|
||||
basicEnemy.speed = 0.5;
|
||||
basicEnemy.color = 'orange'
|
||||
basicEnemy.impactDamage = 2;
|
||||
return basicEnemy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ShootingEnemy extends BasicEnemy implements Shooting {
|
||||
private shootCooldown: number = 0;
|
||||
private shootInterval: number;
|
||||
private projectiles: Projectile[] = []
|
||||
|
||||
constructor(position: Vector, enemyStats: EnemyStats) {
|
||||
super(position, enemyStats);
|
||||
}
|
||||
|
||||
removeProjectile(projectile: Projectile) {
|
||||
this.projectiles = this.projectiles.filter(item => item !== projectile)
|
||||
}
|
||||
|
||||
act() {
|
||||
super.act();
|
||||
if(this.shootCooldown <= 0) {
|
||||
this.createProjectile()
|
||||
this.shootCooldown = this.shootInterval;
|
||||
}
|
||||
this.shootCooldown -= 1;
|
||||
}
|
||||
|
||||
createProjectile() {
|
||||
let stats = new ProjectileStats()
|
||||
.withPiercings(0)
|
||||
.withSize(1)
|
||||
.withDamage(5)
|
||||
.withSpeed(2)
|
||||
let projectile = StraightProjectile.createStraightProjectile(this.world, this._position, this.world.player.position, this, stats)
|
||||
this.projectiles.push(projectile)
|
||||
return projectile
|
||||
}
|
||||
|
||||
static spawnShootingEnemy(world: World, position?: Vector) {
|
||||
world.addEnemy(this.generateShootingEnemy(world, position))
|
||||
}
|
||||
|
||||
static generateShootingEnemy(world: World, position?: Vector) {
|
||||
if(position === undefined) {
|
||||
position = world.randomPlace()
|
||||
}
|
||||
let enemyStats = new EnemyStats().withHealthFactor(world.getEnemyHealthFactor());;
|
||||
let shootingEnemy = new ShootingEnemy(position, enemyStats);
|
||||
shootingEnemy.size = 5;
|
||||
shootingEnemy.world = world;
|
||||
shootingEnemy.speed = 0.5;
|
||||
shootingEnemy.color = 'green'
|
||||
shootingEnemy.impactDamage = 2;
|
||||
shootingEnemy.shootInterval = 100
|
||||
return shootingEnemy
|
||||
}
|
||||
}
|
||||
|
||||
export class HealthEnemy extends Enemy {
|
||||
|
||||
constructor(position: Vector, enemyStats: EnemyStats) {
|
||||
super(position, enemyStats);
|
||||
}
|
||||
|
||||
protected color: string;
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
fillDot(this._position, this.size, this.color, ctx)
|
||||
}
|
||||
|
||||
|
||||
move() {
|
||||
}
|
||||
|
||||
act() {
|
||||
super.act();
|
||||
}
|
||||
|
||||
die() {
|
||||
HealthPack.spawnHealthPack(this.world, this._position)
|
||||
}
|
||||
|
||||
static spawnHealthEnemy(world: World, position?: Vector) {
|
||||
world.addEnemy(this.createHealthEnemy(world, position))
|
||||
}
|
||||
|
||||
static createHealthEnemy(world: World, position?: Vector) {
|
||||
if(position === undefined) {
|
||||
position = world.randomPlace()
|
||||
}
|
||||
let enemyStats = new EnemyStats().withHealthFactor(world.getEnemyHealthFactor());;
|
||||
let basicEnemy = new HealthEnemy(position, enemyStats);
|
||||
basicEnemy.size = 5;
|
||||
basicEnemy.world = world;
|
||||
basicEnemy.speed = 0;
|
||||
basicEnemy.color = 'purple'
|
||||
return basicEnemy;
|
||||
}
|
||||
|
||||
|
||||
getSize() {
|
||||
return this.size
|
||||
}
|
||||
}
|
||||
|
||||
export class ContainerEnemy extends Enemy {
|
||||
|
||||
private drops: KillChanceTable;
|
||||
constructor(position: Vector, enemyStats: EnemyStats) {
|
||||
super(position, enemyStats);
|
||||
this.status.health = 5;
|
||||
this.drops = new KillChanceTable();
|
||||
ItemManagement.getItemsWithRarityFactor().forEach(drop => {
|
||||
this.drops.addDrop(drop)
|
||||
})
|
||||
this.drops.calculateProbs()
|
||||
}
|
||||
|
||||
protected color: string;
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
fillDot(this._position, this.size, this.color, ctx)
|
||||
}
|
||||
|
||||
move() {
|
||||
}
|
||||
|
||||
act() {
|
||||
super.act();
|
||||
}
|
||||
|
||||
die() {
|
||||
let draw = this.drops.draw();
|
||||
if(draw) {
|
||||
let item = draw.creationMethod(this);
|
||||
ItemDrop.spawnItemDrop(this.world, item, this._position)
|
||||
}
|
||||
}
|
||||
|
||||
spawnHealthPack(enemy: ContainerEnemy) {
|
||||
HealthPack.spawnHealthPack(enemy.world, enemy._position)
|
||||
}
|
||||
|
||||
spawnLevelUp(enemy: ContainerEnemy) {
|
||||
LevelDrop.spawnLevelDrop(enemy.world, enemy._position)
|
||||
}
|
||||
|
||||
spawnEnemy(enemy: ContainerEnemy) {
|
||||
ShootingEnemy.spawnShootingEnemy(enemy.world, enemy._position)
|
||||
}
|
||||
|
||||
static spawnContainerEnemy(world: World, position?: Vector) {
|
||||
world.addEnemy(this.createContainerEnemy(world, position))
|
||||
}
|
||||
|
||||
static createContainerEnemy(world: World, position?: Vector) {
|
||||
if(position === undefined) {
|
||||
position = world.randomPlace()
|
||||
}
|
||||
let enemyStats = new EnemyStats().withHealthFactor(world.getEnemyHealthFactor());;
|
||||
let basicEnemy = new ContainerEnemy(position, enemyStats);
|
||||
basicEnemy.size = 5;
|
||||
basicEnemy.world = world;
|
||||
basicEnemy.speed = 0;
|
||||
basicEnemy.color = 'brown'
|
||||
return basicEnemy;
|
||||
}
|
||||
|
||||
|
||||
getSize() {
|
||||
return this.size
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class KillChanceTable {
|
||||
private chances: ChanceEntry[] = []
|
||||
|
||||
addDrop(entry: ChanceEntry) {
|
||||
this.chances.push(entry)
|
||||
}
|
||||
|
||||
calculateProbs() {
|
||||
let sum = this.chances.reduce((sum, entry) => sum + entry.chance, 0)
|
||||
this.chances.forEach(value => value.chance /= sum)
|
||||
}
|
||||
|
||||
draw() {
|
||||
if(this.chances.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
let change = Math.random();
|
||||
for (const value of this.chances) {
|
||||
change -= value.chance;
|
||||
if(change <= 0) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return this.chances[this.chances.length - 1]
|
||||
}
|
||||
}
|
||||
177
absurd-survivors/src/Player.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
import type {Acting, Drawable, Healthy, Item, Weapon} from "./interfaces.ts";
|
||||
import {Vector} from "./base.ts";
|
||||
import {fillDot, getCoordinatesSplit} from "./utils.ts";
|
||||
import {PlayerStats} from "./stats.ts";
|
||||
import {PlayerStatus} from "./status.ts";
|
||||
import {World} from "./World.ts";
|
||||
import { NumberDisplayParticle} from "./particles.ts";
|
||||
|
||||
export class Player implements Drawable, Acting, Healthy {
|
||||
private _position: Vector;
|
||||
private _baseStats: PlayerStats;
|
||||
private _effectiveStats: PlayerStats;
|
||||
private _tempStats: PlayerStats;
|
||||
private _color: string;
|
||||
|
||||
private _status: PlayerStatus;
|
||||
private _weapons: Weapon[] = []
|
||||
private _items: Item[] = []
|
||||
private _healTick: number = 0;
|
||||
private static readonly HEAL_TICK_INTERVAL = 20;
|
||||
private _world: World;
|
||||
|
||||
// temp
|
||||
private _speed: Vector;
|
||||
private _toHeal: number = 0;
|
||||
|
||||
constructor(position: Vector) {
|
||||
this._position = position;
|
||||
this._effectiveStats = new PlayerStats()
|
||||
}
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
fillDot(this.position, this._effectiveStats.size, this._color, ctx)
|
||||
this._weapons.forEach(weapon => weapon.draw(ctx))
|
||||
}
|
||||
|
||||
public static generatePlayer(position?: Vector): Player {
|
||||
if(position === undefined) {
|
||||
position = new Vector(500, 500)
|
||||
}
|
||||
let player = new Player(position);
|
||||
player._color = 'blue';
|
||||
player._baseStats = PlayerStats.defaultPlayerStats();
|
||||
let tempStats = new PlayerStats();
|
||||
tempStats.resetToBasic()
|
||||
player._tempStats = tempStats;
|
||||
player.statsChanged()
|
||||
player._speed = new Vector(0, 0)
|
||||
player._status = new PlayerStatus(10, 0, 0);
|
||||
return player;
|
||||
}
|
||||
|
||||
addWeapon(weapon: Weapon) {
|
||||
let weaponCount = this._weapons.length + 1;
|
||||
let points = getCoordinatesSplit(weaponCount)
|
||||
for (let i = 0; i < points.length - 1; i++){
|
||||
const value = points[i];
|
||||
let affectedWeapon = this._weapons[i];
|
||||
affectedWeapon.setOffset(value.multiply(affectedWeapon.getSize()))
|
||||
}
|
||||
weapon.setOffset(points[points.length - 1].multiply(weapon.getSize()))
|
||||
this._weapons.push(weapon)
|
||||
}
|
||||
|
||||
addItem(item: Item) {
|
||||
this._items.push(item)
|
||||
}
|
||||
|
||||
set world(value: World) {
|
||||
this._world = value;
|
||||
}
|
||||
|
||||
move(direction: Vector) {
|
||||
this._position = this.position.add(direction)
|
||||
}
|
||||
|
||||
takeDamage(damage: number) {
|
||||
NumberDisplayParticle.spawnNumberParticle(this._world, damage, this._position, 'red')
|
||||
this._status.health -= damage;
|
||||
}
|
||||
|
||||
statsChanged() {
|
||||
this._effectiveStats.resetToBasic()
|
||||
this._effectiveStats.mergeStats(this._baseStats)
|
||||
this._effectiveStats.mergeStats(this._tempStats)
|
||||
}
|
||||
|
||||
heal(amount: number) {
|
||||
this._status.health += amount;
|
||||
this._status.health = Math.min(this._status.health, this._effectiveStats.health)
|
||||
}
|
||||
|
||||
get health(): number {
|
||||
return this._status.health;
|
||||
}
|
||||
|
||||
get position(): Vector {
|
||||
return this._position;
|
||||
}
|
||||
|
||||
get color(): string {
|
||||
return this._color;
|
||||
}
|
||||
|
||||
get effectiveStats(): PlayerStats {
|
||||
return this._effectiveStats;
|
||||
}
|
||||
|
||||
get status(): PlayerStatus {
|
||||
return this._status;
|
||||
}
|
||||
|
||||
get speed(): Vector {
|
||||
return this._speed;
|
||||
}
|
||||
|
||||
act() {
|
||||
this._weapons.forEach(weapon => weapon.act())
|
||||
}
|
||||
|
||||
die() {
|
||||
}
|
||||
|
||||
getPosition(): Vector {
|
||||
return this._position;
|
||||
}
|
||||
|
||||
getSize() {
|
||||
return this._effectiveStats.size
|
||||
}
|
||||
|
||||
dead() {
|
||||
return this.status.dead
|
||||
}
|
||||
|
||||
changeBaseStat(value: number, statFun: (stats: PlayerStats, value: number) => void) {
|
||||
this._baseStats.changeStat(value, statFun)
|
||||
this.statsChanged()
|
||||
}
|
||||
|
||||
changeTempStat(value: number, statFun: (stats: PlayerStats, value: number) => void) {
|
||||
this._tempStats.changeStat(value, statFun)
|
||||
this.statsChanged()
|
||||
}
|
||||
|
||||
increaseLevel() {
|
||||
this.status.increaseLevel()
|
||||
this._baseStats.increaseLevel()
|
||||
this._weapons.forEach(weapon => {
|
||||
weapon.increaseLevel()
|
||||
})
|
||||
this.statsChanged()
|
||||
}
|
||||
|
||||
level() {
|
||||
return this.status.level
|
||||
}
|
||||
|
||||
isHurt() {
|
||||
return this.health < this._effectiveStats.health
|
||||
}
|
||||
|
||||
tick(seconds: number, tick: number) {
|
||||
this._healTick += 1;
|
||||
if((this._healTick % Player.HEAL_TICK_INTERVAL) == 0 && this.isHurt()) {
|
||||
let healed = this._effectiveStats.healthRegen / seconds
|
||||
this._toHeal += healed;
|
||||
if(this._toHeal >= 1) {
|
||||
let toHealNow = this._toHeal - (this._toHeal % 1);
|
||||
this._toHeal -= toHealNow;
|
||||
this.heal(toHealNow);
|
||||
NumberDisplayParticle.spawnNumberParticle(this._world, toHealNow, this.position, 'green')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
221
absurd-survivors/src/World.ts
Normal file
@@ -0,0 +1,221 @@
|
||||
import {Enemy} from "./Enemies.ts";
|
||||
import {Player} from "./Player.ts";
|
||||
import {Projectile } from "./projectile.ts";
|
||||
import {Vector} from "./base.ts";
|
||||
import type {Drop, Particle, Placeable} from "./interfaces.ts";
|
||||
|
||||
export class World {
|
||||
private _enemies: ObjectContainer<Enemy> = new ObjectContainer<Enemy>()
|
||||
private _projectiles: ObjectContainer<Projectile> = new ObjectContainer<Projectile>();
|
||||
private _drops: ObjectContainer<Drop> = new ObjectContainer<Drop>();
|
||||
private _particles: ObjectContainer<Particle> = new ObjectContainer();
|
||||
private _player: Player;
|
||||
private readonly _ctx: CanvasRenderingContext2D;
|
||||
private _size: Vector;
|
||||
private _tick: number = 0;
|
||||
private static readonly TICK_INTERVAL = 10;
|
||||
private timeStamp: Date;
|
||||
private startTimeStamp: Date;
|
||||
|
||||
constructor(player: Player, ctx: CanvasRenderingContext2D, size: Vector) {
|
||||
this._player = player;
|
||||
this._ctx = ctx;
|
||||
this._size = size;
|
||||
this.timeStamp = new Date();
|
||||
this.startTimeStamp = new Date();
|
||||
}
|
||||
|
||||
enemiesAct() {
|
||||
this._enemies.items.forEach(enemy => enemy.act())
|
||||
this._enemies.clean()
|
||||
this._projectiles.items.forEach(projectile => projectile.act())
|
||||
this._projectiles.clean()
|
||||
this._drops.items.forEach(drop => drop.act())
|
||||
this._drops.clean()
|
||||
this._particles.items.forEach(particle => particle.act())
|
||||
this._particles.clean()
|
||||
}
|
||||
|
||||
draw() {
|
||||
this._enemies.items.forEach(enemy => enemy.draw(this._ctx))
|
||||
this._drops.items.forEach(drop => drop.draw(this._ctx))
|
||||
this._projectiles.items.forEach(projectile => projectile.draw(this._ctx))
|
||||
this._particles.items.forEach(particle => particle.draw(this._ctx))
|
||||
this._player.draw(this._ctx);
|
||||
}
|
||||
|
||||
addProjectile(projectile: Projectile) {
|
||||
this._projectiles.add(projectile)
|
||||
}
|
||||
|
||||
addParticle(particle: Particle) {
|
||||
this._particles.add(particle)
|
||||
}
|
||||
|
||||
addDrop(drop: Drop) {
|
||||
this._drops.add(drop)
|
||||
}
|
||||
|
||||
removeDrop(drop: Drop) {
|
||||
this._drops.scheduleRemoval(drop)
|
||||
}
|
||||
|
||||
removeParticle(particle: Particle) {
|
||||
this._particles.scheduleRemoval(particle)
|
||||
}
|
||||
|
||||
removeEnemy(enemy: Enemy) {
|
||||
this._enemies.scheduleRemoval(enemy)
|
||||
}
|
||||
|
||||
removeProjectile(projectile: Projectile) {
|
||||
this._projectiles.scheduleRemoval(projectile)
|
||||
}
|
||||
|
||||
|
||||
movePlayer(vector: Vector) {
|
||||
this._player.position.x += vector.x;
|
||||
this._player.position.y += vector.y;
|
||||
this._player.position.x = Math.min(this.size.x - this._player.getSize(), this._player.position.x)
|
||||
this._player.position.x = Math.max(this._player.getSize(), this._player.position.x)
|
||||
this._player.position.y = Math.min(this.size.y -this._player.getSize(), this._player.position.y)
|
||||
this._player.position.y = Math.max(this._player.getSize(), this._player.position.y)
|
||||
}
|
||||
|
||||
maxValue() {
|
||||
return Math.max(this.size.x, this.size.y)
|
||||
}
|
||||
|
||||
get size(): Vector {
|
||||
return this._size;
|
||||
}
|
||||
|
||||
get tick(): number {
|
||||
return this._tick;
|
||||
}
|
||||
|
||||
getSecondsPassed() {
|
||||
return (this.timeStamp.getTime() - this.startTimeStamp.getTime()) / 1000
|
||||
}
|
||||
|
||||
getEnemyHealthFactor() {
|
||||
return this.getSecondsPassed() / 30;
|
||||
}
|
||||
|
||||
triggerTick() {
|
||||
this._tick += 1;
|
||||
if((this._tick % World.TICK_INTERVAL) == 0) {
|
||||
let currentTimeStamp = new Date();
|
||||
let seconds = (currentTimeStamp.getTime() - this.timeStamp.getTime()) / 1000;
|
||||
this._player.tick(seconds, this._tick);
|
||||
this._particles.items.forEach(particle => particle.tick(seconds, this._tick))
|
||||
this.timeStamp = currentTimeStamp;
|
||||
}
|
||||
}
|
||||
|
||||
outside(position: Vector): boolean {
|
||||
return position.x > this.size.x || position.y > this.size.y || position.x < 0 || position.y < 0
|
||||
}
|
||||
|
||||
addEnemy(enemy: Enemy) {
|
||||
this._enemies.add(enemy)
|
||||
}
|
||||
|
||||
randomPlace(): Vector {
|
||||
return new Vector(this.size.x * Math.random(), this.size.y * Math.random())
|
||||
}
|
||||
|
||||
getClosestTargetTo(point: Vector, range?: number): [number, Placeable | undefined] | undefined {
|
||||
return this.getClosestTargetToButNot(point, undefined, range)
|
||||
}
|
||||
|
||||
getFarthestTargetButWithin(point: Vector, range?: number): [number, Placeable | undefined] | undefined {
|
||||
let currentTarget;
|
||||
let currentDistance = Number.MAX_SAFE_INTEGER;
|
||||
this._enemies.items.forEach(enemy => {
|
||||
let distance = point.distanceTo(enemy.getPosition());
|
||||
if(range && distance > range) {
|
||||
return;
|
||||
}
|
||||
if((range - distance) < currentDistance) {
|
||||
currentDistance = distance;
|
||||
currentTarget = enemy
|
||||
}
|
||||
})
|
||||
if(currentTarget) {
|
||||
return [currentDistance, currentTarget];
|
||||
}
|
||||
}
|
||||
|
||||
getClosestTargetToButNot(point: Vector, placeable?: Placeable, range?: number): [number, Placeable | undefined] | undefined {
|
||||
return this.getClosestTargetToButNotArray(point, [placeable], range)
|
||||
}
|
||||
|
||||
getClosestTargetToButNotArray(point: Vector, placeAbles?: [Placeable | undefined], range?: number): [number, Placeable | undefined] | undefined {
|
||||
let currentTarget;
|
||||
let currentDistance = Number.MAX_SAFE_INTEGER;
|
||||
this._enemies.items.forEach(enemy => {
|
||||
if(placeAbles && placeAbles.indexOf(enemy) !== -1) {
|
||||
return;
|
||||
}
|
||||
let distance = point.distanceTo(enemy.getPosition());
|
||||
if(range && distance > range) {
|
||||
return;
|
||||
}
|
||||
if(distance < currentDistance) {
|
||||
currentDistance = distance;
|
||||
currentTarget = enemy
|
||||
}
|
||||
})
|
||||
if(currentTarget) {
|
||||
return [currentDistance, currentTarget];
|
||||
}
|
||||
}
|
||||
|
||||
getAllInRange(point: Vector, range: number): Enemy[] {
|
||||
let found = [];
|
||||
this._enemies.items.forEach(enemy => {
|
||||
let distance = point.distanceTo(enemy.getPosition());
|
||||
if(range && distance < range) {
|
||||
found.push(enemy)
|
||||
}
|
||||
});
|
||||
return found;
|
||||
}
|
||||
|
||||
get player(): Player {
|
||||
return this._player;
|
||||
}
|
||||
}
|
||||
|
||||
class ObjectContainer<T> {
|
||||
private _items: T[] = [];
|
||||
private _itemsToRemove: T[] = [];
|
||||
|
||||
constructor() {
|
||||
this._items = []
|
||||
this._itemsToRemove = []
|
||||
}
|
||||
|
||||
scheduleRemoval(item: T) {
|
||||
this._itemsToRemove.push(item)
|
||||
}
|
||||
|
||||
clean() {
|
||||
this._itemsToRemove.forEach(value => this.remove(value))
|
||||
this._itemsToRemove = []
|
||||
}
|
||||
|
||||
private remove(itemToRemove: T) {
|
||||
this._items = this._items.filter(item => item !== itemToRemove)
|
||||
}
|
||||
|
||||
add(item: T) {
|
||||
this._items.push(item)
|
||||
}
|
||||
|
||||
|
||||
get items(): T[] {
|
||||
return this._items;
|
||||
}
|
||||
}
|
||||
167
absurd-survivors/src/base.ts
Normal file
@@ -0,0 +1,167 @@
|
||||
import type {Healthy, Placeable} from "./interfaces.ts";
|
||||
|
||||
export class Vector {
|
||||
|
||||
constructor(private _x: number, private _y: number) {
|
||||
}
|
||||
|
||||
static createVector(tip: Vector, shaft: Vector): Vector {
|
||||
return new Vector(tip.x - shaft.x, tip.y - shaft.y);
|
||||
}
|
||||
|
||||
static zero() {
|
||||
return new Vector(0, 0)
|
||||
}
|
||||
|
||||
normalize(): Vector {
|
||||
let length = this.vecLength();
|
||||
return new Vector(this.x / length, this.y / length)
|
||||
}
|
||||
|
||||
vecLength(): number {
|
||||
return Math.sqrt(this.x * this.x + this.y * this.y);
|
||||
}
|
||||
|
||||
clone() {
|
||||
return new Vector(this.x, this.y)
|
||||
}
|
||||
|
||||
distanceTo(point: Vector): number {
|
||||
return Math.sqrt(Math.pow(this.x - point.x, 2) + Math.pow(this.y - point.y, 2));
|
||||
}
|
||||
|
||||
add(vec: Vector): Vector {
|
||||
return new Vector(this._x + vec._x, this._y + vec._y)
|
||||
}
|
||||
|
||||
minus(vec: Vector): Vector {
|
||||
return new Vector(this.x - vec._x, this.y - vec.y)
|
||||
}
|
||||
|
||||
multiply(number: number): Vector {
|
||||
return new Vector(this.x * number, this.y * number)
|
||||
}
|
||||
|
||||
multiplyVec(vec: Vector): Vector {
|
||||
return new Vector(this.x * vec._x, this.y * vec.y)
|
||||
}
|
||||
|
||||
negate(): Vector {
|
||||
return this.multiply(-1)
|
||||
}
|
||||
|
||||
dotProduct(vector: Vector): number {
|
||||
return (this._x * vector._x + this._y * vector._y) / Math.pow(vector.vecLength(), 2);
|
||||
}
|
||||
|
||||
dotProduct2(vector: Vector): number {
|
||||
return (this._x * vector._x + this._y * vector._y)
|
||||
}
|
||||
|
||||
angleTo(vector: Vector): number {
|
||||
return Math.acos(this.dotProduct2(vector) / (this.vecLength() * vector.vecLength()))
|
||||
}
|
||||
|
||||
rotate(angle: number) {
|
||||
let c = Math.cos(angle);
|
||||
let s = Math.sin(angle)
|
||||
let x = this._x * c - this._y * s
|
||||
let y = this._x * s + this._y * c
|
||||
return new Vector(x, y)
|
||||
}
|
||||
|
||||
get x(): number {
|
||||
return this._x;
|
||||
}
|
||||
|
||||
set x(value: number) {
|
||||
this._x = value;
|
||||
}
|
||||
|
||||
get y(): number {
|
||||
return this._y;
|
||||
}
|
||||
|
||||
set y(value: number) {
|
||||
this._y = value;
|
||||
}
|
||||
}
|
||||
|
||||
export class Cooldown {
|
||||
private _currentValue;
|
||||
private _totalValue;
|
||||
|
||||
|
||||
constructor(totalValue) {
|
||||
this._totalValue = totalValue;
|
||||
this._currentValue = 0
|
||||
}
|
||||
|
||||
cooledDown(): boolean {
|
||||
return this.currentValue <= 0;
|
||||
}
|
||||
|
||||
get currentValue(): number {
|
||||
return this._currentValue;
|
||||
}
|
||||
|
||||
decreaseCooldown() {
|
||||
this._currentValue -= 1;
|
||||
}
|
||||
|
||||
resetCooldown() {
|
||||
this._currentValue = this._totalValue;
|
||||
}
|
||||
}
|
||||
|
||||
export class Point implements Placeable {
|
||||
|
||||
private position: Vector;
|
||||
|
||||
|
||||
constructor(position: Vector) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
getPosition(): Vector {
|
||||
return this.position;
|
||||
}
|
||||
|
||||
getSize() {
|
||||
}
|
||||
|
||||
move(any?: any) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class DeadPoint implements Placeable, Healthy {
|
||||
|
||||
private position: Vector;
|
||||
|
||||
|
||||
constructor(position: Vector) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
getPosition(): Vector {
|
||||
return this.position;
|
||||
}
|
||||
|
||||
getSize() {
|
||||
}
|
||||
|
||||
move(any?: any) {
|
||||
}
|
||||
|
||||
dead() {
|
||||
return true;
|
||||
}
|
||||
|
||||
die() {
|
||||
}
|
||||
|
||||
takeDamage(damage: number) {
|
||||
}
|
||||
|
||||
}
|
||||
160
absurd-survivors/src/drop.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
import type {Drop, Item} from "./interfaces.ts";
|
||||
import {World} from "./World.ts";
|
||||
import {fillDot, moveInDirectionOf} from "./utils.ts";
|
||||
import {Vector} from "./base.ts";
|
||||
import {rarityColor} from "./items.ts";
|
||||
|
||||
export abstract class BasicDrop implements Drop {
|
||||
protected world: World;
|
||||
protected _position: Vector;
|
||||
protected _color: string;
|
||||
protected size: number;
|
||||
|
||||
constructor(world: World, position: Vector) {
|
||||
this.world = world;
|
||||
this._position = position.clone();
|
||||
}
|
||||
|
||||
getPosition(): Vector {
|
||||
return this._position;
|
||||
}
|
||||
|
||||
move() {
|
||||
}
|
||||
|
||||
pickup() {
|
||||
}
|
||||
|
||||
act() {
|
||||
let distanceToPlayer = this._position.distanceTo(this.world.player.position);
|
||||
if(distanceToPlayer < (this.world.player.effectiveStats.size + this.size)) {
|
||||
this.pickup()
|
||||
this.world.removeDrop(this)
|
||||
} else if(distanceToPlayer < this.world.player.effectiveStats.pullRange) {
|
||||
let speedFactor = 125 / distanceToPlayer;
|
||||
this._position = moveInDirectionOf(this._position, this.world.player.position, speedFactor)
|
||||
}
|
||||
}
|
||||
|
||||
abstract draw(ctx: CanvasRenderingContext2D);
|
||||
|
||||
getSize() {
|
||||
return this.size
|
||||
}
|
||||
|
||||
tick(seconds: number, tick: number) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class MoneyDrop extends BasicDrop {
|
||||
|
||||
private worth: number;
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
fillDot(this._position, this.size, this._color, ctx)
|
||||
}
|
||||
|
||||
pickup() {
|
||||
this.world.player.status.wealth += this.worth
|
||||
}
|
||||
|
||||
static spawnMoneyDrop(world: World, position?: Vector) {
|
||||
world.addDrop(this.createMoneyDrop(world, position))
|
||||
}
|
||||
|
||||
static createMoneyDrop(world: World, position?: Vector): MoneyDrop {
|
||||
if(!position) {
|
||||
position = world.randomPlace()
|
||||
}
|
||||
let drop = new MoneyDrop(world, position)
|
||||
drop.worth = 1;
|
||||
drop.size = 1;
|
||||
drop._color = 'orange';
|
||||
return drop;
|
||||
}
|
||||
}
|
||||
|
||||
export class HealthPack extends BasicDrop {
|
||||
private healAmount: number;
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
fillDot(this._position, this.size, this._color, ctx)
|
||||
}
|
||||
|
||||
pickup() {
|
||||
this.world.player.heal(this.healAmount)
|
||||
}
|
||||
|
||||
static spawnHealthPack(world: World, position?: Vector) {
|
||||
world.addDrop(this.createHealthPack(world, position))
|
||||
}
|
||||
|
||||
static createHealthPack(world: World, position?: Vector) {
|
||||
if(!position) {
|
||||
position = world.randomPlace()
|
||||
}
|
||||
let drop = new HealthPack(world, position)
|
||||
drop.healAmount = 5;
|
||||
drop.size = 2;
|
||||
drop._color = 'green';
|
||||
return drop;
|
||||
}
|
||||
}
|
||||
|
||||
export class LevelDrop extends BasicDrop {
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
fillDot(this._position, this.size, this._color, ctx)
|
||||
}
|
||||
|
||||
pickup() {
|
||||
this.world.player.increaseLevel()
|
||||
}
|
||||
|
||||
static spawnLevelDrop(world: World, position?: Vector) {
|
||||
world.addDrop(this.createLevelDrop(world, position))
|
||||
}
|
||||
static createLevelDrop(world: World, position?: Vector): LevelDrop {
|
||||
if(!position) {
|
||||
position = world.randomPlace()
|
||||
}
|
||||
let drop = new LevelDrop(world, position)
|
||||
drop.size = 5;
|
||||
drop._color = 'blue';
|
||||
return drop;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ItemDrop extends BasicDrop {
|
||||
|
||||
private item: Item;
|
||||
|
||||
|
||||
constructor(world: World, position: Vector, item: Item) {
|
||||
super(world, position);
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
pickup() {
|
||||
this.item.pickup(this.world.player, this.world)
|
||||
}
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
ctx.fillStyle = rarityColor(this.item.getRarity())
|
||||
ctx.fillText(this.item.name() + '', this._position.x, this._position.y)
|
||||
}
|
||||
|
||||
static spawnItemDrop(world: World, item: Item, position?: Vector) {
|
||||
world.addDrop(this.createItemDrop(world, item, position))
|
||||
}
|
||||
|
||||
static createItemDrop(world: World, item: Item, position?: Vector) {
|
||||
if(!position) {
|
||||
position = world.randomPlace()
|
||||
}
|
||||
let drop = new ItemDrop(world, position, item)
|
||||
drop.size = 3
|
||||
return drop
|
||||
}
|
||||
}
|
||||
7
absurd-survivors/src/instance.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type {Healthy} from "./interfaces.ts";
|
||||
|
||||
export class InstanceOfUtils {
|
||||
static instanceOfHealthy(object: any): object is Healthy {
|
||||
return 'takeDamage' in object;
|
||||
}
|
||||
}
|
||||
80
absurd-survivors/src/interfaces.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import {Vector} from "./base.ts";
|
||||
import type {Player} from "./Player.ts";
|
||||
import type {Rarity} from "./items.ts";
|
||||
import type {World} from "./World.ts";
|
||||
|
||||
export interface Acting {
|
||||
act()
|
||||
tick(seconds: number, tick: number)
|
||||
}
|
||||
|
||||
export interface Healthy {
|
||||
takeDamage(damage: number);
|
||||
die();
|
||||
dead();
|
||||
}
|
||||
|
||||
export interface Leveling {
|
||||
increaseLevel();
|
||||
level()
|
||||
}
|
||||
|
||||
export interface Item {
|
||||
pickup(player: Player, world: World);
|
||||
name(): string
|
||||
getRarity(): Rarity;
|
||||
}
|
||||
|
||||
export interface ChanceEntry {
|
||||
chance: number;
|
||||
creationMethod: (any: any) => any;
|
||||
}
|
||||
|
||||
export interface Drop extends Drawable, Acting {
|
||||
pickup()
|
||||
}
|
||||
|
||||
export interface Particle extends Drawable, Placeable, Acting {
|
||||
|
||||
}
|
||||
|
||||
export interface Placeable {
|
||||
move(any?: any)
|
||||
getSize();
|
||||
getPosition(): Vector;
|
||||
}
|
||||
|
||||
export interface MouseInteracting {
|
||||
hit(pos: Vector): boolean
|
||||
clickAction(pos: Vector): void
|
||||
}
|
||||
|
||||
export interface MouseInterActingContainer {
|
||||
mouseDown(pos: Vector)
|
||||
}
|
||||
|
||||
export interface Projectile extends Drawable {
|
||||
|
||||
}
|
||||
|
||||
export interface Equipment {
|
||||
getOffset(): Vector;
|
||||
setOffset(vec: Vector);
|
||||
}
|
||||
|
||||
export interface Weapon extends Drawable, Equipment, Leveling {
|
||||
act()
|
||||
}
|
||||
|
||||
export interface Shooting {
|
||||
createProjectile(): Projectile;
|
||||
removeProjectile(projectile: Projectile)
|
||||
}
|
||||
|
||||
export interface Drawable extends Placeable {
|
||||
draw(ctx: CanvasRenderingContext2D);
|
||||
}
|
||||
|
||||
export interface DrawContainer {
|
||||
draw(ctx: CanvasRenderingContext2D);
|
||||
}
|
||||
271
absurd-survivors/src/items.ts
Normal file
@@ -0,0 +1,271 @@
|
||||
import type {ChanceEntry, Item} from "./interfaces.ts";
|
||||
import {Player} from "./Player.ts";
|
||||
import {randomItem} from "./utils.ts";
|
||||
import {ChainBall, HomingPistol, Pistol, Spear, SpreadWeapon} from "./weapons.ts";
|
||||
import type {World} from "./World.ts";
|
||||
import {PlayerStats} from "./stats.ts";
|
||||
|
||||
export enum Rarity {
|
||||
GARBAGE= 'GARBAGE',
|
||||
COMMON = 'COMMON',
|
||||
UNCOMMON = 'UNCOMMON',
|
||||
RARE = 'RARE',
|
||||
EPIC = 'EPIC',
|
||||
LEGENDARY = 'LEGENDARY',
|
||||
GODLY = 'GODLY'
|
||||
}
|
||||
|
||||
export class ItemManagement {
|
||||
|
||||
private static ITEMS: Item[] = []
|
||||
|
||||
static addItem(item: Item) {
|
||||
this.ITEMS.push(item)
|
||||
}
|
||||
|
||||
static getItemsWithRarityFactor(): ChanceEntry[] {
|
||||
let items: ChanceEntry[] = []
|
||||
this.ITEMS.forEach((item) => {
|
||||
items.push({chance: rarityWeight(item.getRarity()), creationMethod: () => item})
|
||||
})
|
||||
return items;
|
||||
}
|
||||
|
||||
static getRandomItem() {
|
||||
return randomItem(this.ITEMS)
|
||||
}
|
||||
|
||||
static initializeItems() {
|
||||
this.ITEMS.push(new SpeedUp())
|
||||
this.ITEMS.push(new HealthUp())
|
||||
this.ITEMS.push(new HomingPistolItem())
|
||||
this.ITEMS.push(new PistolItem())
|
||||
this.ITEMS.push(new SpreadWeaponItem())
|
||||
this.ITEMS.push(new ChainBallWeaponItem())
|
||||
this.ITEMS.push(new PullRangeUp())
|
||||
this.ITEMS.push(new SpearWeaponItem())
|
||||
this.ITEMS.push(new DamageUpFactor())
|
||||
this.ITEMS.push(new DamageFactorUp())
|
||||
this.ITEMS.push(new DamageFactorUpFactor())
|
||||
this.ITEMS.push(new DamageUp())
|
||||
}
|
||||
}
|
||||
|
||||
export function rarityWeight(rarity: Rarity): number {
|
||||
switch (rarity) {
|
||||
case Rarity.GARBAGE: return 80;
|
||||
case Rarity.COMMON: return 65;
|
||||
case Rarity.UNCOMMON: return 50;
|
||||
case Rarity.RARE: return 30;
|
||||
case Rarity.EPIC: return 15;
|
||||
case Rarity.LEGENDARY: return 5;
|
||||
case Rarity.GODLY: return 1;
|
||||
}
|
||||
}
|
||||
|
||||
export function rarityColor(rarity: Rarity): string {
|
||||
switch (rarity) {
|
||||
case Rarity.GARBAGE: return 'white';
|
||||
case Rarity.COMMON: return 'gray';
|
||||
case Rarity.UNCOMMON: return 'blue';
|
||||
case Rarity.RARE: return 'green';
|
||||
case Rarity.EPIC: return 'orange';
|
||||
case Rarity.LEGENDARY: return 'violett';
|
||||
case Rarity.GODLY: return 'red';
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class BaseItem implements Item {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
pickup(player: Player, world: World) {
|
||||
player.addItem(this)
|
||||
}
|
||||
|
||||
abstract name();
|
||||
abstract getRarity(): Rarity;
|
||||
}
|
||||
|
||||
export class SpeedUp extends BaseItem {
|
||||
pickup(player: Player, world: World) {
|
||||
player.changeBaseStat(1, PlayerStats.increaseSpeed)
|
||||
super.pickup(player, world)
|
||||
}
|
||||
|
||||
name() {
|
||||
return 'speed'
|
||||
}
|
||||
|
||||
getRarity(): Rarity {
|
||||
return Rarity.LEGENDARY;
|
||||
}
|
||||
}
|
||||
|
||||
export class PullRangeUp extends BaseItem {
|
||||
pickup(player: Player, world: World) {
|
||||
player.changeBaseStat(1.1, PlayerStats.factorPullRange)
|
||||
super.pickup(player, world)
|
||||
}
|
||||
|
||||
name() {
|
||||
return 'pull range'
|
||||
}
|
||||
|
||||
getRarity(): Rarity {
|
||||
return Rarity.COMMON;
|
||||
}
|
||||
}
|
||||
|
||||
export class HealthUp extends BaseItem {
|
||||
pickup(player: Player, world: World) {
|
||||
let healthAmount = 1;
|
||||
player.changeBaseStat(healthAmount, PlayerStats.increaseHealth)
|
||||
player.heal(healthAmount)
|
||||
super.pickup(player, world)
|
||||
}
|
||||
|
||||
name() {
|
||||
return 'health'
|
||||
}
|
||||
|
||||
getRarity(): Rarity {
|
||||
return Rarity.COMMON;
|
||||
}
|
||||
}
|
||||
|
||||
export class HomingPistolItem extends BaseItem {
|
||||
pickup(player: Player, world: World) {
|
||||
player.addWeapon(HomingPistol.generateHomingPistol(world))
|
||||
super.pickup(player, world)
|
||||
}
|
||||
|
||||
name() {
|
||||
return 'homingp'
|
||||
}
|
||||
|
||||
getRarity(): Rarity {
|
||||
return Rarity.RARE;
|
||||
}
|
||||
}
|
||||
|
||||
export class PistolItem extends BaseItem {
|
||||
pickup(player: Player, world: World) {
|
||||
player.addWeapon(Pistol.generatePistol(world))
|
||||
super.pickup(player, world)
|
||||
}
|
||||
|
||||
name() {
|
||||
return 'pistol'
|
||||
}
|
||||
|
||||
getRarity(): Rarity {
|
||||
return Rarity.RARE;
|
||||
}
|
||||
}
|
||||
|
||||
export class SpreadWeaponItem extends BaseItem {
|
||||
pickup(player: Player, world: World) {
|
||||
player.addWeapon(SpreadWeapon.generateSpreadWeapon(world))
|
||||
super.pickup(player, world)
|
||||
}
|
||||
|
||||
name() {
|
||||
return 'spreadp'
|
||||
}
|
||||
|
||||
getRarity(): Rarity {
|
||||
return Rarity.EPIC;
|
||||
}
|
||||
}
|
||||
|
||||
export class ChainBallWeaponItem extends BaseItem {
|
||||
pickup(player: Player, world: World) {
|
||||
player.addWeapon(ChainBall.createChainBall(world))
|
||||
super.pickup(player, world)
|
||||
}
|
||||
|
||||
name() {
|
||||
return 'chain ball'
|
||||
}
|
||||
|
||||
getRarity(): Rarity {
|
||||
return Rarity.EPIC;
|
||||
}
|
||||
}
|
||||
|
||||
export class SpearWeaponItem extends BaseItem {
|
||||
pickup(player: Player, world: World) {
|
||||
player.addWeapon(Spear.createSpear(world))
|
||||
super.pickup(player, world)
|
||||
}
|
||||
|
||||
name() {
|
||||
return 'spear'
|
||||
}
|
||||
|
||||
getRarity(): Rarity {
|
||||
return Rarity.EPIC;
|
||||
}
|
||||
}
|
||||
|
||||
export class DamageFactorUpFactor extends BaseItem {
|
||||
pickup(player: Player, world: World) {
|
||||
player.changeBaseStat(1, PlayerStats.factorDamageFactor)
|
||||
super.pickup(player, world)
|
||||
}
|
||||
|
||||
name() {
|
||||
return 'damageFactorUpFactor'
|
||||
}
|
||||
|
||||
getRarity(): Rarity {
|
||||
return Rarity.LEGENDARY;
|
||||
}
|
||||
}
|
||||
|
||||
export class DamageUp extends BaseItem {
|
||||
pickup(player: Player, world: World) {
|
||||
player.changeBaseStat(1, PlayerStats.increaseDamage)
|
||||
super.pickup(player, world)
|
||||
}
|
||||
|
||||
name() {
|
||||
return 'damageUp'
|
||||
}
|
||||
|
||||
getRarity(): Rarity {
|
||||
return Rarity.COMMON;
|
||||
}
|
||||
}
|
||||
|
||||
export class DamageUpFactor extends BaseItem {
|
||||
pickup(player: Player, world: World) {
|
||||
player.changeBaseStat(1, PlayerStats.factorDamage)
|
||||
super.pickup(player, world)
|
||||
}
|
||||
|
||||
name() {
|
||||
return 'damageUpFactor'
|
||||
}
|
||||
|
||||
getRarity(): Rarity {
|
||||
return Rarity.LEGENDARY;
|
||||
}
|
||||
}
|
||||
|
||||
export class DamageFactorUp extends BaseItem {
|
||||
pickup(player: Player, world: World) {
|
||||
player.changeBaseStat(1, PlayerStats.increaseDamageFactor)
|
||||
super.pickup(player, world)
|
||||
}
|
||||
|
||||
name() {
|
||||
return 'damageFactorUp'
|
||||
}
|
||||
|
||||
getRarity(): Rarity {
|
||||
return Rarity.UNCOMMON;
|
||||
}
|
||||
}
|
||||
175
absurd-survivors/src/main.ts
Normal file
@@ -0,0 +1,175 @@
|
||||
import './style.css'
|
||||
|
||||
import {docReady} from "canvas-common";
|
||||
import {World} from "./World.ts";
|
||||
import {Player} from "./Player.ts";
|
||||
import {Vector} from "./base.ts";
|
||||
import {BasicEnemy, ContainerEnemy, HealthEnemy, ShootingEnemy} from "./Enemies.ts";
|
||||
import {HUD} from "./ui.ts";
|
||||
import {Pistol} from "./weapons.ts";
|
||||
import {ItemManagement} from "./items.ts";
|
||||
|
||||
let hud: HUD;
|
||||
let world: World;
|
||||
let config: Config;
|
||||
let state: WorldState;
|
||||
let ctx: CanvasRenderingContext2D;
|
||||
let canvas;
|
||||
|
||||
export class Config {
|
||||
private _fps: number = 60;
|
||||
|
||||
get fps(): number {
|
||||
return this._fps;
|
||||
}
|
||||
}
|
||||
|
||||
export class WorldState {
|
||||
private _ended: boolean = false;
|
||||
|
||||
|
||||
get ended(): boolean {
|
||||
return this._ended;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function updateCanvas() {
|
||||
ctx.clearRect(0, 0, world.size.x, world.size.y);
|
||||
hud.draw(ctx)
|
||||
if(!state.ended) {
|
||||
world.triggerTick()
|
||||
world.enemiesAct()
|
||||
world.player.act()
|
||||
world.draw()
|
||||
for(let key in keys) {
|
||||
if(keys[key].state) {
|
||||
keys[key].fun(keys[key].intensity)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ctx.fillText('End', 15, 15)
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
requestAnimationFrame(updateCanvas);
|
||||
}, 1000 / config.fps)
|
||||
|
||||
}
|
||||
|
||||
function makeKey(char, fun) {
|
||||
keys[char] = {
|
||||
state: false,
|
||||
fun: fun
|
||||
}
|
||||
}
|
||||
|
||||
let keys = {};
|
||||
makeKey('w', function (intensity: number) {
|
||||
world.movePlayer(new Vector(0, -world.player.effectiveStats.speed * intensity))
|
||||
})
|
||||
makeKey('s', function (intensity: number) {
|
||||
world.movePlayer(new Vector(0, world.player.effectiveStats.speed * intensity))
|
||||
})
|
||||
makeKey('a', function (intensity: number) {
|
||||
world.movePlayer(new Vector(-world.player.effectiveStats.speed * intensity, 0))
|
||||
})
|
||||
makeKey('d', function (intensity: number) {
|
||||
world.movePlayer(new Vector(world.player.effectiveStats.speed * intensity, 0))
|
||||
})
|
||||
|
||||
|
||||
function keyUp(event) {
|
||||
if(event.key in keys) {
|
||||
keys[event.key].state = false;
|
||||
keys[event.key].intensity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function keyDown(event) {
|
||||
if(event.key in keys) {
|
||||
keys[event.key].state = true;
|
||||
keys[event.key].intensity = 1;
|
||||
}
|
||||
}
|
||||
|
||||
document.onkeyup = keyUp;
|
||||
document.onkeydown = keyDown;
|
||||
docReady(function () {
|
||||
canvas = document.getElementById('canvas');
|
||||
|
||||
canvas.width = window.innerWidth;
|
||||
|
||||
canvas.height = window.innerHeight;
|
||||
|
||||
|
||||
ctx = canvas.getContext("2d");
|
||||
config = new Config();
|
||||
let player = Player.generatePlayer(new Vector(window.innerWidth /2, window.innerHeight / 2));
|
||||
|
||||
world = new World(player, ctx, new Vector(window.innerWidth, window.innerHeight));
|
||||
player.world = world; // not sure if this is great design
|
||||
state = new WorldState();
|
||||
|
||||
setInterval(() => {
|
||||
BasicEnemy.spawnBasicEnemy(world)
|
||||
}, 1_000)
|
||||
|
||||
setInterval(() => {
|
||||
ShootingEnemy.spawnShootingEnemy(world)
|
||||
}, 3_000)
|
||||
|
||||
setInterval(() => {
|
||||
HealthEnemy.spawnHealthEnemy(world)
|
||||
}, 15_000)
|
||||
|
||||
setInterval(() => {
|
||||
ContainerEnemy.spawnContainerEnemy(world)
|
||||
}, 10_000)
|
||||
|
||||
player.addWeapon(Pistol.generatePistol(world))
|
||||
hud = new HUD(world, keys);
|
||||
|
||||
canvas.onmousedown = (event) => {
|
||||
event.preventDefault()
|
||||
let pos = new Vector(event.x, event.y)
|
||||
hud.mouseDown(pos)
|
||||
}
|
||||
canvas.onmouseup = (event) => {
|
||||
event.preventDefault()
|
||||
let pos = new Vector(event.x, event.y)
|
||||
hud.mouseUp(pos)
|
||||
}
|
||||
|
||||
canvas.onmousemove = (event) => {
|
||||
event.preventDefault()
|
||||
let pos = new Vector(event.x, event.y)
|
||||
hud.mouseMove(pos)
|
||||
}
|
||||
|
||||
canvas.addEventListener("touchstart", (event) => {
|
||||
event.preventDefault()
|
||||
let touch = event.touches[0]
|
||||
let pos = new Vector(touch.clientX, touch.clientY)
|
||||
hud.mouseDown(pos)
|
||||
});
|
||||
|
||||
canvas.addEventListener("touchend", (event) => {
|
||||
event.preventDefault()
|
||||
let pos = new Vector(event.clientX, event.clientY)
|
||||
hud.mouseUp(pos)
|
||||
});
|
||||
|
||||
canvas.addEventListener("touchmove", (event) => {
|
||||
event.preventDefault()
|
||||
let touch = event.touches[0]
|
||||
let pos = new Vector(touch.clientX, touch.clientY)
|
||||
hud.mouseMove(pos)
|
||||
});
|
||||
|
||||
ItemManagement.initializeItems()
|
||||
|
||||
requestAnimationFrame(updateCanvas);
|
||||
|
||||
})
|
||||
|
||||
75
absurd-survivors/src/particles.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import type {Particle} from "./interfaces.ts";
|
||||
import {Vector} from "./base.ts";
|
||||
import {World} from "./World.ts";
|
||||
|
||||
abstract class BaseParticle implements Particle {
|
||||
protected _position: Vector;
|
||||
protected world: World;
|
||||
|
||||
|
||||
constructor(position: Vector, world: World) {
|
||||
this._position = position.clone();
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
getPosition(): Vector {
|
||||
return this._position;
|
||||
}
|
||||
|
||||
getSize() {
|
||||
}
|
||||
|
||||
move(any?: any) {
|
||||
this._position = this._position.add(new Vector(0, -0.5))
|
||||
}
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
}
|
||||
|
||||
act() {
|
||||
this.move()
|
||||
}
|
||||
|
||||
tick(seconds: number, tick: number) {
|
||||
}
|
||||
}
|
||||
|
||||
export class NumberDisplayParticle extends BaseParticle {
|
||||
private number: number;
|
||||
private secondsToDisplay: number = 2;
|
||||
private alreadyDisplayed: number = 0;
|
||||
private color: string;
|
||||
|
||||
constructor(position: Vector, world: World, healthAmount: number, color: string) {
|
||||
super(position, world);
|
||||
this.number = healthAmount;
|
||||
this.color = color
|
||||
}
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
ctx.fillStyle = this.color;
|
||||
ctx.fillText(this.number + '', this._position.x, this._position.y);
|
||||
}
|
||||
|
||||
tick(seconds: number, tick: number) {
|
||||
this.alreadyDisplayed += seconds;
|
||||
if(this.alreadyDisplayed > this.secondsToDisplay) {
|
||||
this.world.removeParticle(this)
|
||||
}
|
||||
}
|
||||
|
||||
static spawnNumberParticle(world: World, health: number, position: Vector, color?: string) {
|
||||
if(!color) {
|
||||
color = 'red'
|
||||
}
|
||||
world.addParticle(this.createNumberParticle(world, health, position, color))
|
||||
}
|
||||
|
||||
static createNumberParticle(world: World, health: number, position: Vector, color?: string) {
|
||||
if(!color) {
|
||||
color = 'red'
|
||||
}
|
||||
let particle = new NumberDisplayParticle(position, world, health, color)
|
||||
return particle
|
||||
}
|
||||
}
|
||||
326
absurd-survivors/src/projectile.ts
Normal file
@@ -0,0 +1,326 @@
|
||||
import type {Acting, Placeable, Healthy } from "./interfaces.ts";
|
||||
import type {Vector} from "./base.ts";
|
||||
import {World} from "./World.ts";
|
||||
import {DeadPoint, Vector} from "./base.ts";
|
||||
import {
|
||||
circleLineCollision,
|
||||
fillDot,
|
||||
getCoordinatesSplit,
|
||||
moveInDirectionOf,
|
||||
pointOnLineWithinLine,
|
||||
straightMove,
|
||||
toRad
|
||||
} from "./utils.ts";
|
||||
import {InstanceOfUtils} from "./instance.ts";
|
||||
import {ChainBall, MeleeWeapon} from "./weapons.ts";
|
||||
import type {Enemy} from "./Enemies.ts";
|
||||
import {ProjectileStats} from "./stats.ts";
|
||||
import {ProjectileStatus} from "./status.ts";
|
||||
|
||||
export abstract class Projectile implements Acting, Placeable {
|
||||
|
||||
protected position: Vector;
|
||||
protected speedVec: Vector;
|
||||
protected world: World;
|
||||
protected parent: any;
|
||||
protected color: string
|
||||
protected stats: ProjectileStats;
|
||||
protected status: ProjectileStatus;
|
||||
protected lastPosition: Vector;
|
||||
protected secondToLastPosition?: Vector
|
||||
protected lastColliding?: Placeable;
|
||||
|
||||
constructor(position: Vector, speedVec: Vector, stats: ProjectileStats, world: World, parent: any) {
|
||||
this.position = position.clone();
|
||||
this.speedVec = speedVec.clone();
|
||||
this.world = world;
|
||||
this.parent = parent;
|
||||
this.stats = stats;
|
||||
this.status = new ProjectileStatus(stats.piercings)
|
||||
}
|
||||
|
||||
die() {
|
||||
this.world.removeProjectile(this)
|
||||
}
|
||||
|
||||
act() {
|
||||
this.move()
|
||||
if(this.parent !== this.world.player) {
|
||||
if(this.position.distanceTo(this.world.player.position) < (this.stats.size + this.world.player.effectiveStats.size) && this.status.collisionCooldown.cooledDown()) {
|
||||
this.impactPlayer()
|
||||
this.status.collisionCooldown.resetCooldown()
|
||||
}
|
||||
} else if(this.parent === this.world.player) {
|
||||
let closestTargetTo = this.world.getClosestTargetToButNot(this.position, this.lastColliding);
|
||||
if(closestTargetTo !== undefined && closestTargetTo[1] !== undefined) {
|
||||
let target: Placeable = closestTargetTo[1]!;
|
||||
if(target.getPosition().distanceTo(this.position) < (this.stats.size + target.getSize())
|
||||
|| circleLineCollision(target.getPosition(), target.getSize(), this.position, this.lastPosition)) {
|
||||
if(target !== this.lastColliding) {
|
||||
if(InstanceOfUtils.instanceOfHealthy(target)) {
|
||||
let healthy = target as Healthy;
|
||||
healthy.takeDamage(this.stats.damage)
|
||||
if(!this.status.hasPiercingLeft()) {
|
||||
this.die()
|
||||
}
|
||||
this.status.decreasePiercings()
|
||||
} else {
|
||||
this.die()
|
||||
}
|
||||
}
|
||||
this.lastColliding = target;
|
||||
} else {
|
||||
this.lastColliding = undefined;
|
||||
}
|
||||
} else {
|
||||
this.lastColliding = undefined;
|
||||
}
|
||||
}
|
||||
this.status.collisionCooldown.decreaseCooldown()
|
||||
this.checkWorldBorder()
|
||||
}
|
||||
|
||||
checkWorldBorder() {
|
||||
if(this.world.outside(this.position)) {
|
||||
this.die()
|
||||
}
|
||||
}
|
||||
|
||||
impactPlayer() {
|
||||
this.world.player.takeDamage(this.stats.damage)
|
||||
this.die()
|
||||
};
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
fillDot(this.position, this.stats.size, this.color, ctx)
|
||||
}
|
||||
|
||||
move() {
|
||||
this.secondToLastPosition = this.lastPosition;
|
||||
this.lastPosition = this.position.clone()
|
||||
}
|
||||
|
||||
getPosition(): Vector {
|
||||
return this.position;
|
||||
}
|
||||
|
||||
getSize() {
|
||||
return this.stats.size
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class StraightProjectile extends Projectile {
|
||||
|
||||
|
||||
constructor(position: Vector, dirVector: Vector, stats: ProjectileStats, world: World, parent: any) {
|
||||
super(position, dirVector, stats, world, parent);
|
||||
}
|
||||
|
||||
move() {
|
||||
super.move()
|
||||
this.position = straightMove(this.position, this.speedVec)
|
||||
}
|
||||
|
||||
static createStraightProjectile(world: World, start: Vector, targetPosition: Vector, parent: any, stats: ProjectileStats, color?: string) {
|
||||
let dirVector = Vector.createVector(targetPosition, start).normalize().multiply(stats.speed);
|
||||
let projectile = new StraightProjectile(start, dirVector, stats, world, parent)
|
||||
projectile.color = color === undefined ? 'red' : color!;
|
||||
world.addProjectile(projectile)
|
||||
return projectile;
|
||||
}
|
||||
}
|
||||
|
||||
export class ChainBallProjectile extends Projectile {
|
||||
private weapon: ChainBall;
|
||||
private movingBack: boolean = false;
|
||||
private target: Vector;
|
||||
private lastHit: Enemy[] = []
|
||||
|
||||
constructor(position: Vector, speedVec: Vector, stats: ProjectileStats, world: World, parent: any, weapon: ChainBall, target: Vector) {
|
||||
super(position, speedVec, stats, world, parent);
|
||||
this.weapon = weapon;
|
||||
this.target = target.clone()
|
||||
}
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
fillDot(this.position, this.stats.size, 'pink', ctx) // todo render the weapon instead
|
||||
}
|
||||
|
||||
act() {
|
||||
this.move()
|
||||
// TODO It seems that the projectile doesnt _quite_ hit the enemy, but is just getting close to it
|
||||
let hitEnemies = this.world.getAllInRange(this.position, this.stats.size * 2);
|
||||
hitEnemies.forEach(value => {
|
||||
if(this.lastHit.indexOf(value) !== -1) {
|
||||
if(InstanceOfUtils.instanceOfHealthy(value)) {
|
||||
let healthy = value as Healthy;
|
||||
healthy.takeDamage(this.stats.damage)
|
||||
}
|
||||
}
|
||||
})
|
||||
this.lastHit = hitEnemies;
|
||||
}
|
||||
|
||||
move() {
|
||||
super.move()
|
||||
if(!this.movingBack) {
|
||||
this.position = straightMove(this.position, this.speedVec)
|
||||
if(this.position.distanceTo(this.target) < this.stats.size) {
|
||||
this.movingBack = true;
|
||||
this.speedVec = this.speedVec.multiply(3)
|
||||
}
|
||||
} else {
|
||||
this.position = moveInDirectionOf(this.position, this.world.player.position, this.speedVec.vecLength())
|
||||
}
|
||||
if(this.movingBack && this.position.distanceTo(this.world.player.position) < (this.stats.size + this.world.player.effectiveStats.size)) {
|
||||
this.weapon.reset();
|
||||
this.die()
|
||||
}
|
||||
}
|
||||
|
||||
static createChainBallProjectile(world: World, start: Vector, targetPosition: Vector, parent: any, stats: ProjectileStats, weapon: MeleeWeapon, color?: string) {
|
||||
let dirVector = Vector.createVector(targetPosition, start).normalize().multiply(stats.speed);
|
||||
let projectile = new ChainBallProjectile(start, dirVector, stats, world, parent, weapon, targetPosition)
|
||||
projectile.color = color === undefined ? 'red' : color!;
|
||||
world.addProjectile(projectile)
|
||||
return projectile;
|
||||
}
|
||||
}
|
||||
|
||||
export class StraightMeleeWeaponProjectile extends Projectile {
|
||||
|
||||
private weapon: MeleeWeapon;
|
||||
private movingBack: boolean = false;
|
||||
private target: Vector;
|
||||
private lastHit: Enemy[] = []
|
||||
|
||||
constructor(position: Vector, speedVec: Vector, stats: ProjectileStats, world: World, parent: any, weapon: ChainBall, target: Vector) {
|
||||
super(position, speedVec, stats, world, parent);
|
||||
this.weapon = weapon;
|
||||
this.target = target.clone()
|
||||
}
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
let position = this.getRealPosition();
|
||||
fillDot(position, this.stats.size, 'brown', ctx) // todo render the weapon instead
|
||||
}
|
||||
|
||||
getRealPosition(): Vector {
|
||||
return this.world.player.getPosition().add(this.position)
|
||||
}
|
||||
|
||||
act() {
|
||||
this.move()
|
||||
let hitEnemies = this.world.getAllInRange(this.getRealPosition(), this.stats.size * 2);
|
||||
hitEnemies.forEach(value => {
|
||||
if(this.lastHit.indexOf(value) !== -1) {
|
||||
if(InstanceOfUtils.instanceOfHealthy(value)) {
|
||||
let healthy = value as Healthy;
|
||||
healthy.takeDamage(this.stats.damage)
|
||||
}
|
||||
}
|
||||
})
|
||||
this.lastHit = hitEnemies;
|
||||
}
|
||||
|
||||
move() {
|
||||
super.move()
|
||||
if(!this.movingBack) {
|
||||
this.position = straightMove(this.position, this.speedVec)
|
||||
if(this.position.distanceTo(this.target) < this.stats.size) {
|
||||
this.movingBack = true;
|
||||
this.speedVec = this.speedVec.multiply(3)
|
||||
}
|
||||
} else {
|
||||
this.position = moveInDirectionOf(this.position, new Vector(0, 0), this.speedVec.vecLength())
|
||||
}
|
||||
if(this.movingBack && this.position.distanceTo(new Vector(0, 0)) < (this.stats.size + this.world.player.effectiveStats.size)) {
|
||||
this.weapon.reset();
|
||||
this.die()
|
||||
}
|
||||
}
|
||||
|
||||
static createStraightMeleeProjectile(world: World, start: Vector, targetPosition: Vector, parent: any, stats: ProjectileStats, weapon: MeleeWeapon, color?: string) {
|
||||
let dirVector = Vector.createVector(targetPosition, start).normalize().multiply(stats.speed);
|
||||
let projectile = new StraightMeleeWeaponProjectile(start, dirVector, stats, world, parent, weapon, targetPosition)
|
||||
projectile.color = color === undefined ? 'red' : color!;
|
||||
world.addProjectile(projectile)
|
||||
return projectile;
|
||||
}
|
||||
}
|
||||
|
||||
export class HomingProjectile extends Projectile {
|
||||
|
||||
private target: Placeable;
|
||||
|
||||
constructor(position: Vector, speedVec: Vector, stats: ProjectileStats, world: World, parent: any, target: Placeable) {
|
||||
super(position, speedVec, stats, world, parent);
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
move() {
|
||||
super.move()
|
||||
this.position = moveInDirectionOf(this.position, this.target.getPosition(), this.speedVec.vecLength())
|
||||
if(InstanceOfUtils.instanceOfHealthy(this.target)) {
|
||||
let target = this.target as Healthy
|
||||
if(target.dead()) {
|
||||
let closestTargetTo = this.world.getClosestTargetTo(this.position)
|
||||
|
||||
let oldTargetDirection = Vector.createVector(this.target.getPosition(), this.position)
|
||||
let justMovedDirection = Vector.createVector(this.position, this.lastPosition).normalize()
|
||||
let olderMovedDirection: Vector;
|
||||
if(this.secondToLastPosition !== undefined) {
|
||||
olderMovedDirection = Vector.createVector(this.lastPosition, this.secondToLastPosition).normalize();
|
||||
} else {
|
||||
olderMovedDirection = new Vector(0, 1)
|
||||
}
|
||||
if (closestTargetTo !== undefined && closestTargetTo[1] !== undefined) {
|
||||
let newTargetPosition = closestTargetTo[1]!.getPosition();
|
||||
let newDir = Vector.createVector(newTargetPosition, this.position)
|
||||
let newDirAngle = newDir.angleTo(olderMovedDirection);
|
||||
if(Math.abs(newDirAngle) <= toRad(30)) {
|
||||
this.target = closestTargetTo[1]!;
|
||||
} else {
|
||||
if(pointOnLineWithinLine(this.target.getPosition(), this.lastPosition, this.position)) {
|
||||
justMovedDirection = olderMovedDirection
|
||||
}
|
||||
this.target = new DeadPoint(this.position.add(justMovedDirection.multiply(this.world.maxValue())))
|
||||
}
|
||||
} else {
|
||||
if(pointOnLineWithinLine(this.target.getPosition(), this.lastPosition, this.position)) {
|
||||
justMovedDirection = olderMovedDirection
|
||||
}
|
||||
this.target = new DeadPoint(this.position.add(justMovedDirection.multiply(Math.max(this.world.size.x, this.world.size.y))))
|
||||
}
|
||||
}
|
||||
}
|
||||
this.checkWorldBorder()
|
||||
}
|
||||
|
||||
static createHomingProjectile(world: World, start: Vector, parent: any, target: Placeable, stats: ProjectileStats, color?: string) {
|
||||
|
||||
let projectile = new HomingProjectile(start, new Vector(0, stats.speed), stats, world, parent, target)
|
||||
projectile.color = color === undefined ? 'red' : color!;
|
||||
world.addProjectile(projectile)
|
||||
return projectile;
|
||||
}
|
||||
|
||||
|
||||
die() {
|
||||
if(this.stats.deathSplit && this.stats.deathSplit > 0 && Math.random() > this.stats.deathSplitChance) {
|
||||
let splits = this.stats.deathSplit;
|
||||
let directionalVectors = getCoordinatesSplit(splits);
|
||||
let stats = new ProjectileStats()
|
||||
.withSize(this.stats.size / 2)
|
||||
.withDamage(this.stats.damage / 2)
|
||||
.withSpeed(this.stats.speed / 2)
|
||||
directionalVectors.forEach(value => {
|
||||
let target = this.position.add(value.multiply(this.world.maxValue()))
|
||||
StraightProjectile.createStraightProjectile(this.world, this.position, target, this.parent, stats, 'white')
|
||||
})
|
||||
}
|
||||
super.die();
|
||||
}
|
||||
}
|
||||
|
||||
235
absurd-survivors/src/stats.ts
Normal file
@@ -0,0 +1,235 @@
|
||||
|
||||
export class PlayerStats {
|
||||
|
||||
private _speed: number;
|
||||
private _size: number;
|
||||
private _health: number;
|
||||
private _pullRange: number;
|
||||
private _weaponRange: number;
|
||||
private _weaponRangeFactor: number;
|
||||
private _healthRegen: number;
|
||||
private _damage: number;
|
||||
private _damageFactor: number;
|
||||
|
||||
constructor() {
|
||||
this._speed = 3;
|
||||
this._size = 5;
|
||||
this._health = 10;
|
||||
this._pullRange = 150;
|
||||
this._weaponRange = 250;
|
||||
this._weaponRangeFactor = 1;
|
||||
this._healthRegen = 0.001;
|
||||
this._damage = 0;
|
||||
this._damageFactor = 0;
|
||||
}
|
||||
|
||||
resetToBasic() {
|
||||
this._speed = 0;
|
||||
this._health = 0;
|
||||
this._pullRange = 0;
|
||||
this._weaponRange = 0;
|
||||
this._weaponRangeFactor = 1;
|
||||
this._healthRegen = 0.001;
|
||||
this._damage = 0;
|
||||
this._damageFactor = 0;
|
||||
}
|
||||
|
||||
increaseLevel() {
|
||||
this._speed *= 1.1;
|
||||
this._health += 1
|
||||
this._pullRange *= 1.1;
|
||||
this._weaponRange *= 1.25
|
||||
this._weaponRangeFactor += 0.1
|
||||
this._healthRegen += 0.1
|
||||
this._damage += 1;
|
||||
this._damageFactor += 0.1;
|
||||
}
|
||||
|
||||
mergeStats(otherStats: PlayerStats) {
|
||||
this._speed += otherStats._speed;
|
||||
this._health += otherStats._health;
|
||||
this._pullRange += otherStats._pullRange;
|
||||
this._weaponRange += otherStats._weaponRange
|
||||
this._weaponRangeFactor += otherStats._weaponRangeFactor;
|
||||
this._healthRegen += otherStats._healthRegen;
|
||||
this._damage += otherStats._damage;
|
||||
this._damageFactor += otherStats._damageFactor
|
||||
}
|
||||
|
||||
clone() {
|
||||
let newStats = new PlayerStats();
|
||||
newStats.mergeStats(this)
|
||||
return newStats;
|
||||
}
|
||||
|
||||
changeStat(value: number, statFun: (stats: PlayerStats, value: number) => void) {
|
||||
statFun(this, value)
|
||||
}
|
||||
|
||||
static increaseSpeed(stats: PlayerStats, value: number) {
|
||||
stats._speed += value
|
||||
}
|
||||
|
||||
static factorSpeed(stats: PlayerStats, value: number) {
|
||||
stats._speed *= value
|
||||
}
|
||||
|
||||
static factorDamage(stats: PlayerStats, value: number) {
|
||||
stats._damage *= value
|
||||
}
|
||||
|
||||
static increaseDamage(stats: PlayerStats, value: number) {
|
||||
stats._damage += value
|
||||
}
|
||||
|
||||
static factorDamageFactor(stats: PlayerStats, value: number) {
|
||||
stats._damageFactor *= value
|
||||
}
|
||||
|
||||
static increaseDamageFactor(stats: PlayerStats, value: number) {
|
||||
stats._damageFactor += value
|
||||
}
|
||||
|
||||
static increasePullRange(stats: PlayerStats, value: number) {
|
||||
stats._pullRange += value
|
||||
}
|
||||
|
||||
static factorPullRange(stats: PlayerStats, value: number) {
|
||||
stats._pullRange *= value
|
||||
}
|
||||
|
||||
static increaseHealth(stats: PlayerStats, value: number) {
|
||||
stats._health += value
|
||||
}
|
||||
|
||||
get speed(): number {
|
||||
return this._speed;
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
return this._size;
|
||||
}
|
||||
|
||||
get pullRange(): number {
|
||||
return this._pullRange;
|
||||
}
|
||||
|
||||
get health(): number {
|
||||
return this._health;
|
||||
}
|
||||
|
||||
get weaponRange(): number {
|
||||
return this._weaponRange
|
||||
}
|
||||
|
||||
get healthRegen(): number {
|
||||
return this._healthRegen;
|
||||
}
|
||||
|
||||
get effectiveWeaponRange(): number {
|
||||
return this._weaponRange * this._weaponRangeFactor;
|
||||
}
|
||||
|
||||
get effectiveDamage(): number {
|
||||
return this._damage * this._damageFactor;
|
||||
}
|
||||
|
||||
public static defaultPlayerStats(): PlayerStats {
|
||||
return new PlayerStats();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class ProjectileStats {
|
||||
|
||||
private _piercings: number;
|
||||
private _size: number;
|
||||
private _damage: number;
|
||||
private _speed: number;
|
||||
private _deathSplit: number;
|
||||
private _deathSplitChance: number;
|
||||
|
||||
constructor() {
|
||||
this._size = 1
|
||||
}
|
||||
|
||||
withPiercings(value: number) {
|
||||
this._piercings = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
withSize(value: number) {
|
||||
this._size = Math.max(value, 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
withDamage(value: number) {
|
||||
this._damage = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
withSpeed(value: number) {
|
||||
this._speed = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
withDeathSplit(value: number) {
|
||||
this._deathSplit = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
withDeathSplitChance(value: number) {
|
||||
this._deathSplitChance = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
get piercings(): number {
|
||||
return this._piercings;
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
return this._size;
|
||||
}
|
||||
|
||||
|
||||
get speed(): number {
|
||||
return this._speed;
|
||||
}
|
||||
|
||||
get damage(): number {
|
||||
return this._damage;
|
||||
}
|
||||
|
||||
|
||||
get deathSplitChance(): number {
|
||||
return this._deathSplitChance;
|
||||
}
|
||||
|
||||
get deathSplit(): number {
|
||||
return this._deathSplit;
|
||||
}
|
||||
}
|
||||
|
||||
export class EnemyStats {
|
||||
private _healthFactor: number;
|
||||
private _baseHealth: number;
|
||||
|
||||
constructor() {
|
||||
this._healthFactor = 1;
|
||||
this._baseHealth = 10
|
||||
}
|
||||
|
||||
withHealthFactor(healthFactor: number) {
|
||||
this._healthFactor = healthFactor;
|
||||
return this
|
||||
}
|
||||
|
||||
withBaseHealth(baseHealth: number) {
|
||||
this._baseHealth = baseHealth;
|
||||
return this
|
||||
}
|
||||
|
||||
getEffectiveHealth() {
|
||||
return this._baseHealth * this._healthFactor
|
||||
}
|
||||
}
|
||||
88
absurd-survivors/src/status.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import {Cooldown} from "./base.ts";
|
||||
|
||||
export class PlayerStatus {
|
||||
constructor(private _health: number,
|
||||
private _wealth: number,
|
||||
private _level: number) {
|
||||
}
|
||||
|
||||
|
||||
get level(): number {
|
||||
return this._level;
|
||||
}
|
||||
|
||||
set level(value: number) {
|
||||
this._level = value;
|
||||
}
|
||||
|
||||
get health(): number {
|
||||
return this._health;
|
||||
}
|
||||
|
||||
set health(value: number) {
|
||||
this._health = value;
|
||||
}
|
||||
|
||||
get dead(): boolean {
|
||||
return this._health <= 0
|
||||
}
|
||||
|
||||
get wealth(): number {
|
||||
return this._wealth;
|
||||
}
|
||||
|
||||
set wealth(value: number) {
|
||||
this._wealth = value;
|
||||
}
|
||||
|
||||
increaseLevel() {
|
||||
this._level += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class EnemyStatus {
|
||||
constructor(private _health: number) {
|
||||
}
|
||||
|
||||
|
||||
get health(): number {
|
||||
return this._health;
|
||||
}
|
||||
|
||||
get dead(): boolean {
|
||||
return this._health <= 0;
|
||||
}
|
||||
|
||||
set health(value: number) {
|
||||
this._health = value;
|
||||
}
|
||||
}
|
||||
|
||||
export class ProjectileStatus {
|
||||
private _piercingsLeft: number;
|
||||
private _collisionCooldown: Cooldown;
|
||||
|
||||
constructor(piercingsLeft: number) {
|
||||
this._piercingsLeft = piercingsLeft;
|
||||
this._collisionCooldown = new Cooldown(10)
|
||||
}
|
||||
|
||||
get piercingsLeft(): number {
|
||||
return this._piercingsLeft;
|
||||
}
|
||||
|
||||
hasPiercingLeft(): boolean {
|
||||
return this.piercingsLeft > 0;
|
||||
}
|
||||
|
||||
|
||||
get collisionCooldown(): Cooldown {
|
||||
return this._collisionCooldown;
|
||||
}
|
||||
|
||||
decreasePiercings() {
|
||||
this._piercingsLeft -= 1;
|
||||
}
|
||||
|
||||
}
|
||||
4
absurd-survivors/src/style.css
Normal file
@@ -0,0 +1,4 @@
|
||||
html, body, div, canvas {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
295
absurd-survivors/src/ui.ts
Normal file
@@ -0,0 +1,295 @@
|
||||
import type {Drawable, DrawContainer, MouseInteracting, MouseInterActingContainer} from "./interfaces.ts";
|
||||
import {World} from "./World.ts";
|
||||
import {Vector} from "./base.ts";
|
||||
import {drawDot, fillDot, isMobile, rectPointIntersection} from "./utils.ts";
|
||||
|
||||
export class HUD implements DrawContainer {
|
||||
private health: PlayerInfo;
|
||||
private controls: Controls | undefined;
|
||||
private world: World;
|
||||
|
||||
constructor(world: World, keys: any) {
|
||||
this.world = world;
|
||||
this.health = new PlayerInfo(world);
|
||||
if (isMobile()) {
|
||||
this.controls = new Controls(world, keys);
|
||||
}
|
||||
}
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
this.health.draw(ctx)
|
||||
if(this.controls) {
|
||||
this.controls.draw(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
mouseDown(pos: Vector) {
|
||||
if(this.controls) {
|
||||
this.controls.mouseDown(pos)
|
||||
}
|
||||
}
|
||||
|
||||
mouseUp(pos: Vector) {
|
||||
if(this.controls) {
|
||||
this.controls.mouseUp(pos)
|
||||
}
|
||||
}
|
||||
|
||||
mouseMove(pos: Vector) {
|
||||
if(this.controls) {
|
||||
this.controls.mouseMove(pos)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class Controls implements DrawContainer, MouseInterActingContainer {
|
||||
|
||||
private world: World;
|
||||
private centerPosition: Vector | undefined;
|
||||
private keys: any;
|
||||
private size: number;
|
||||
|
||||
constructor(world: World, keys: any) {
|
||||
this.world = world;
|
||||
this.keys = keys;
|
||||
this.size = 60;
|
||||
}
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
if(this.isPressed()) {
|
||||
drawDot(this.centerPosition!, this.size, 'white', ctx)
|
||||
}
|
||||
}
|
||||
|
||||
isPressed() {
|
||||
return this.centerPosition !== undefined;
|
||||
}
|
||||
|
||||
mouseDown(pos: Vector) {
|
||||
this.centerPosition = pos
|
||||
}
|
||||
|
||||
mouseUp(pos: Vector) {
|
||||
this.centerPosition = undefined;
|
||||
let keys = ['a', 's', 'd', 'w']
|
||||
keys.forEach(key => {
|
||||
this.keys[key].state = false;
|
||||
this.keys[key].intensity = 0;
|
||||
})
|
||||
this.keys['a'].state = false
|
||||
}
|
||||
|
||||
setKeyTo(key: string, state: boolean, value: number) {
|
||||
this.keys[key].state = state;
|
||||
this.keys[key].intensity = value;
|
||||
}
|
||||
|
||||
mouseMove(pos: Vector) {
|
||||
if(this.isPressed()) {
|
||||
let diff = Vector.createVector(pos, this.centerPosition!);
|
||||
if(isNaN(diff.x) || isNaN(diff.y)) {
|
||||
return;
|
||||
}
|
||||
diff = diff.normalize();
|
||||
if(diff.x > 0) {
|
||||
this.setKeyTo('a', false, 0)
|
||||
this.setKeyTo('d', true, Math.abs(diff.x))
|
||||
} else if(diff.x < 0){
|
||||
this.setKeyTo('d', false, 0)
|
||||
this.setKeyTo('a', true, Math.abs(diff.x))
|
||||
}
|
||||
if(diff.y > 0) {
|
||||
this.setKeyTo('w', false, 0)
|
||||
this.setKeyTo('s', true, Math.abs(diff.y))
|
||||
} else if(diff.y < 0) {
|
||||
this.setKeyTo('s', false, 0)
|
||||
this.setKeyTo('w', true, Math.abs(diff.y))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class PlayerInfo implements DrawContainer {
|
||||
private bar: InfoBar;
|
||||
private statLabels: StatLabel[] = []
|
||||
private world: World;
|
||||
private statLabelBase: Vector;
|
||||
private static readonly STAT_LABEL_HEIGHT_OFFSET: number = 4;
|
||||
|
||||
constructor(world: World) {
|
||||
this.world = world;
|
||||
this.bar = new InfoBar(new Vector(0, 50), 50, 150, () => 'Health', () => this.world.player.status.health, () => this.world.player.effectiveStats.health)
|
||||
this.statLabelBase = new Vector(0, 150)
|
||||
this.statLabels = [
|
||||
new StatLabel(() => 'Money', () => this.world.player.status.wealth),
|
||||
new StatLabel(() => 'Level', () => this.world.player.status.level),
|
||||
new StatLabel(() => 'Speed', () => Math.floor(this.world.player.effectiveStats.speed)),
|
||||
new StatLabel(() => 'Pull range', () => Math.floor(this.world.player.effectiveStats.pullRange)),
|
||||
new StatLabel(() => 'Weapon range', () => Math.floor(this.world.player.effectiveStats.effectiveWeaponRange)),
|
||||
new StatLabel(() => 'Damage', () => Math.floor(this.world.player.effectiveStats.effectiveDamage))
|
||||
]
|
||||
}
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
this.bar.draw(ctx)
|
||||
let metrics = ctx.measureText('I')
|
||||
let upperCaseCharacterSize = new Vector(0, metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent).add(new Vector(0, PlayerInfo.STAT_LABEL_HEIGHT_OFFSET))
|
||||
for (let i = 0; i < this.statLabels.length; i++){
|
||||
const label = this.statLabels[i];
|
||||
label.move(this.statLabelBase.add(upperCaseCharacterSize.multiply(i)))
|
||||
label.draw(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class RectButton implements Drawable, MouseInteracting {
|
||||
protected position: Vector;
|
||||
protected size: Vector;
|
||||
protected borderColor: string = 'light-gray';
|
||||
protected contentColor: string = 'gray';
|
||||
protected label: string;
|
||||
protected action: () => void;
|
||||
protected releaseLambda?: () => void;
|
||||
|
||||
constructor(position: Vector, size: Vector, label: string, actionLambda: () => void, releaseLambda?: () => void) {
|
||||
this.position = position;
|
||||
this.size = size;
|
||||
this.label = label;
|
||||
this.action = actionLambda;
|
||||
this.releaseLambda = releaseLambda;
|
||||
}
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
ctx.beginPath()
|
||||
ctx.fillStyle = this.contentColor;
|
||||
ctx.strokeStyle = this.borderColor;
|
||||
ctx.rect(this.position.x, this.position.y, this.size.x, this.size.y)
|
||||
ctx.fill()
|
||||
ctx.stroke();
|
||||
ctx.fillStyle = 'black'
|
||||
ctx.fillText(this.label, this.position.x + this.size.x / 2, this.position.y + this.size.y / 2)
|
||||
ctx.closePath()
|
||||
}
|
||||
|
||||
getPosition(): Vector {
|
||||
return this.position;
|
||||
}
|
||||
|
||||
getSize() {
|
||||
}
|
||||
|
||||
move(any?: any) {
|
||||
}
|
||||
|
||||
clickAction(pos: Vector) {
|
||||
this.action()
|
||||
}
|
||||
|
||||
releaseAction(pos: Vector) {
|
||||
if(this.releaseLambda) {
|
||||
this.releaseLambda()
|
||||
}
|
||||
}
|
||||
|
||||
hit(pos: Vector): boolean {
|
||||
return rectPointIntersection(this.position, this.size, pos)
|
||||
}
|
||||
}
|
||||
|
||||
export class KeyboardButton extends RectButton {
|
||||
constructor(position: Vector, size: Vector, key: string, keys: any) {
|
||||
super(position, size, key.toUpperCase(),
|
||||
() => { keys[key.toLowerCase()].state = true},
|
||||
() => { keys[key.toLowerCase()].state = false}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export class StatLabel implements Drawable {
|
||||
private position: Vector;
|
||||
private borderColor: string = 'white';
|
||||
private textLambda: () => string;
|
||||
private valueLambda: () => number;
|
||||
|
||||
|
||||
constructor(textLambda: () => string, valueLambda: () => number);
|
||||
constructor(textLambda: () => string, valueLambda: () => number, position?: Vector) {
|
||||
if(!position) {
|
||||
position = new Vector(0, 0)
|
||||
}
|
||||
this.position = position;
|
||||
this.textLambda = textLambda;
|
||||
this.valueLambda = valueLambda;
|
||||
}
|
||||
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = this.borderColor
|
||||
let value = this.valueLambda();
|
||||
let text = this.textLambda();
|
||||
ctx.fillText(`${text}: ${value}`, this.position.x, this.position.y)
|
||||
ctx.fill()
|
||||
}
|
||||
|
||||
getPosition(): Vector {
|
||||
return this.position;
|
||||
}
|
||||
|
||||
move(position: Vector) {
|
||||
this.position = position
|
||||
}
|
||||
|
||||
getSize() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class InfoBar implements Drawable {
|
||||
private position: Vector;
|
||||
private height: number;
|
||||
private width: number;
|
||||
private fillColor: string = 'green';
|
||||
private borderColor: string = 'white';
|
||||
private textLambda: () => string;
|
||||
private valueLambda: () => number;
|
||||
private totalValueLambda: () => number;
|
||||
|
||||
|
||||
constructor(position: Vector, height: number, width: number, textLambda: () => string, valueLambda: () => number, totalValueLambda: () => number) {
|
||||
this.position = position;
|
||||
this.height = height;
|
||||
this.width = width;
|
||||
this.textLambda = textLambda;
|
||||
this.valueLambda = valueLambda;
|
||||
this.totalValueLambda = totalValueLambda;
|
||||
}
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = this.borderColor
|
||||
ctx.strokeRect(this.position.x, this.position.y, this.width, this.height)
|
||||
ctx.fillStyle = this.fillColor;
|
||||
let value = this.valueLambda();
|
||||
let totalValue = this.totalValueLambda();
|
||||
let usedWidth = (value / totalValue) * this.width;
|
||||
ctx.fillRect(this.position.x, this.position.y, usedWidth, this.height)
|
||||
ctx.fillStyle = this.borderColor
|
||||
ctx.fillText(`${value}/${totalValue}`, this.position.x + this.width / 2, this.position.y + this.height / 2)
|
||||
ctx.fill()
|
||||
}
|
||||
|
||||
getPosition(): Vector {
|
||||
return this.position;
|
||||
}
|
||||
|
||||
move(any?: any) {
|
||||
}
|
||||
|
||||
getSize() {
|
||||
}
|
||||
|
||||
}
|
||||
109
absurd-survivors/src/utils.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import {Vector} from "./base.ts";
|
||||
|
||||
export function fillDot(position: Vector, size: number, color: string, ctx: CanvasRenderingContext2D) {
|
||||
ctx.beginPath();
|
||||
ctx.fillStyle = color;
|
||||
ctx.arc(position.x, position.y, size, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
export function isMobile() {
|
||||
// https://stackoverflow.com/questions/11381673/detecting-a-mobile-browser
|
||||
let check = false;
|
||||
(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor);
|
||||
return check;
|
||||
}
|
||||
|
||||
export function drawDot(position: Vector, size: number, color: string, ctx: CanvasRenderingContext2D) {
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = color;
|
||||
ctx.arc(position.x, position.y, size, 0, 2 * Math.PI);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
export function moveInDirectionOf(position: Vector, target: Vector, speedFactor: number): Vector {
|
||||
let playerVector = Vector.createVector(target, position);
|
||||
let direction = playerVector.normalize()
|
||||
return position.add(direction.multiply(speedFactor))
|
||||
}
|
||||
|
||||
export function straightMove(position: Vector, speed: Vector): Vector {
|
||||
return position.add(speed)
|
||||
}
|
||||
|
||||
export function toRad(angle) {
|
||||
return angle / 180 * Math.PI;
|
||||
}
|
||||
|
||||
export function toDegrees(angle) {
|
||||
return angle * 180 / Math.PI
|
||||
}
|
||||
|
||||
export function pointInsideCircle(circleCenter: Vector, radius: number, point: Vector) {
|
||||
return circleCenter.distanceTo(point) < radius;
|
||||
}
|
||||
|
||||
export function linePointCollision(point: Vector, lineStart: Vector, lineEnd: Vector) {
|
||||
let lineLength = Vector.createVector(lineEnd, lineStart).vecLength();
|
||||
let distanceStart = Vector.createVector(lineStart, point).vecLength()
|
||||
let distanceEnd = Vector.createVector(lineEnd, point).vecLength();
|
||||
let buffer = 0.001
|
||||
if((distanceStart + distanceEnd) >= (lineLength - buffer) && (distanceEnd + distanceStart) <= (lineLength + buffer)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function pointOnLineWithinLine(circleCenter: Vector, lineStart: Vector, lineEnd: Vector) {
|
||||
let lineVector = Vector.createVector(lineEnd, lineStart)
|
||||
let vectorCenterLine = Vector.createVector(circleCenter, lineStart)
|
||||
let dot = vectorCenterLine.dotProduct(lineVector)
|
||||
let closestX = lineStart.x + (dot * (lineVector.x))
|
||||
let closestY = lineStart.y + (dot * (lineVector.y))
|
||||
let closestPoint = new Vector(closestX, closestY);
|
||||
return linePointCollision(closestPoint, lineStart, lineEnd);
|
||||
}
|
||||
|
||||
export function circleLineCollision(circleCenter: Vector, radius: number, lineStart: Vector, lineEnd: Vector) {
|
||||
if(pointInsideCircle(circleCenter, radius, lineStart) || pointInsideCircle(circleCenter, radius, lineEnd)) {
|
||||
return true;
|
||||
}
|
||||
let lineVector = Vector.createVector(lineEnd, lineStart)
|
||||
let vectorCenterLine = Vector.createVector(circleCenter, lineStart)
|
||||
let dot = vectorCenterLine.dotProduct(lineVector)
|
||||
let closestX = lineStart.x + (dot * (lineVector.x))
|
||||
let closestY = lineStart.y + (dot * (lineVector.y))
|
||||
let closestPoint = new Vector(closestX, closestY);
|
||||
let onSegment = linePointCollision(closestPoint, lineStart, lineEnd)
|
||||
if(!onSegment) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return pointInsideCircle(circleCenter, radius, closestPoint);
|
||||
}
|
||||
|
||||
export function getCoordinatesSplit(amount: number) {
|
||||
let angle = 2 * Math.PI / amount;
|
||||
let points: Vector[] = [];
|
||||
for (let i = 0; i < amount; i++) {
|
||||
let x = Math.cos(angle * i)
|
||||
let y = Math.sin(angle * i)
|
||||
points.push(new Vector(x, y))
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
export function randomItem(items: any[]) {
|
||||
return items[Math.floor(Math.random() * items.length)]
|
||||
}
|
||||
|
||||
export function rectPointIntersection(topLeft: Vector, size: Vector, point: Vector) {
|
||||
if (topLeft.x + size.x >= point.x &&
|
||||
topLeft.x <= point.x &&
|
||||
topLeft.y + size.y >= point.y &&
|
||||
topLeft.y <= point.y) {
|
||||
return true
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
1
absurd-survivors/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
406
absurd-survivors/src/weapons.ts
Normal file
@@ -0,0 +1,406 @@
|
||||
import type {Weapon} from "./interfaces.ts";
|
||||
import {fillDot, toRad} from "./utils.ts";
|
||||
import {Player} from "./Player.ts";
|
||||
import {
|
||||
HomingProjectile,
|
||||
Projectile,
|
||||
StraightProjectile,
|
||||
ChainBallProjectile,
|
||||
StraightMeleeWeaponProjectile
|
||||
} from "./projectile.ts";
|
||||
import {World} from "./World.ts";
|
||||
import {Vector} from "./base.ts";
|
||||
import {ProjectileStats} from "./stats.ts";
|
||||
|
||||
export abstract class BasicWeapon implements Weapon {
|
||||
protected offset: Vector;
|
||||
protected readonly player: Player
|
||||
protected readonly world: World;
|
||||
protected color: string;
|
||||
protected size: number;
|
||||
protected stats: WeaponStats;
|
||||
protected _level: number;
|
||||
|
||||
constructor(world: World, stats: WeaponStats) {
|
||||
this.player = world.player;
|
||||
this.world = world;
|
||||
this.stats = stats;
|
||||
this._level = 1;
|
||||
}
|
||||
|
||||
act() {
|
||||
}
|
||||
|
||||
increaseLevel() {
|
||||
this._level += 1;
|
||||
this.stats.increase()
|
||||
}
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
}
|
||||
|
||||
getPosition(): Vector {
|
||||
return this.player.position.add(this.offset);
|
||||
}
|
||||
|
||||
move(any?: any) {
|
||||
}
|
||||
|
||||
getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
getDamage() {
|
||||
return this.stats.damage + this.player.effectiveStats.effectiveDamage;
|
||||
}
|
||||
|
||||
getOffset(): Vector {
|
||||
return this.offset;
|
||||
}
|
||||
|
||||
setOffset(vec: Vector) {
|
||||
this.offset = vec;
|
||||
}
|
||||
|
||||
level() {
|
||||
return this._level
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class RangeWeapon extends BasicWeapon {
|
||||
|
||||
protected projectiles: [Projectile] = []
|
||||
protected shootCooldown: number = 0;
|
||||
|
||||
abstract createProjectile(): boolean;
|
||||
|
||||
act() {
|
||||
if(this.shootCooldown <= 0) {
|
||||
if(this.createProjectile()) {
|
||||
this.shootCooldown = this.stats.shootInterval;
|
||||
}
|
||||
}
|
||||
this.shootCooldown -= 1;
|
||||
}
|
||||
|
||||
calculateRange(): number {
|
||||
return this.world.player.effectiveStats.effectiveWeaponRange + this.stats.effectiveWeaponRange;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export abstract class MeleeWeapon extends RangeWeapon {
|
||||
protected launched: boolean;
|
||||
|
||||
act() {
|
||||
if(this.shootCooldown <= 0) {
|
||||
if(this.createProjectile()) {
|
||||
this.launched = true;
|
||||
this.shootCooldown = 1;
|
||||
}
|
||||
}
|
||||
if(!this.launched) {
|
||||
this.shootCooldown -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.shootCooldown = this.stats.shootInterval
|
||||
this.launched = false;
|
||||
}
|
||||
|
||||
calculateRange(): number {
|
||||
return this.stats.effectiveWeaponRange;
|
||||
}
|
||||
}
|
||||
|
||||
export class Spear extends MeleeWeapon {
|
||||
protected launched: boolean;
|
||||
|
||||
createProjectile(): boolean {
|
||||
let range = this.calculateRange()
|
||||
let closestTargetTo = this.world.getFarthestTargetButWithin(this.world.player.position, range);
|
||||
if(closestTargetTo !== undefined && closestTargetTo[1] !== undefined) {
|
||||
let stats = new ProjectileStats()
|
||||
.withPiercings(1000)
|
||||
.withSize(3)
|
||||
.withDamage(this.getDamage())
|
||||
.withSpeed(this.stats.projectileSpeed);
|
||||
let offsetVector = Vector.createVector(closestTargetTo[1]!.getPosition(), this.player.position).multiply(1.1);
|
||||
if(offsetVector.vecLength() < 15) {
|
||||
offsetVector = offsetVector.normalize().multiply(40)
|
||||
}
|
||||
let projectile = StraightMeleeWeaponProjectile.createStraightMeleeProjectile(this.world, new Vector(0, 0), offsetVector, this.player, stats, this)
|
||||
this.projectiles.push(projectile)
|
||||
return true
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static createSpear(world: World, offset?: Vector) {
|
||||
if(!offset) {
|
||||
offset = new Vector(5, 5)
|
||||
}
|
||||
let stats = new WeaponStats()
|
||||
.withProjectileSpeed(5)
|
||||
.withDamage(15)
|
||||
.withWeaponRange(150)
|
||||
.withShootInterval(50)
|
||||
let pistol = new Spear(world, stats)
|
||||
pistol.offset = offset;
|
||||
pistol.size = 7;
|
||||
pistol.color = 'brown';
|
||||
return pistol;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ChainBall extends MeleeWeapon {
|
||||
|
||||
createProjectile(): boolean {
|
||||
let range = this.calculateRange()
|
||||
let closestTargetTo = this.world.getFarthestTargetButWithin(this.world.player.position, range);
|
||||
if(closestTargetTo !== undefined && closestTargetTo[1] !== undefined) {
|
||||
let stats = new ProjectileStats()
|
||||
.withPiercings(1000)
|
||||
.withSize(3)
|
||||
.withDamage(this.getDamage())
|
||||
.withSpeed(this.stats.projectileSpeed);
|
||||
let projectile = ChainBallProjectile.createChainBallProjectile(this.world, this.getPosition(), closestTargetTo[1]!.getPosition(), this.player, stats, this)
|
||||
this.projectiles.push(projectile)
|
||||
return true
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static createChainBall(world: World, offset?: Vector) {
|
||||
if(!offset) {
|
||||
offset = new Vector(5, 5)
|
||||
}
|
||||
let stats = new WeaponStats()
|
||||
.withProjectileSpeed(3)
|
||||
.withDamage(15)
|
||||
.withWeaponRange(150)
|
||||
.withShootInterval(20)
|
||||
let pistol = new ChainBall(world, stats)
|
||||
pistol.offset = offset;
|
||||
pistol.size = 4;
|
||||
pistol.color = 'gray';
|
||||
return pistol;
|
||||
}
|
||||
}
|
||||
|
||||
export class HomingPistol extends RangeWeapon {
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
fillDot(this.getPosition(), 1, this.color, ctx)
|
||||
}
|
||||
|
||||
createProjectile(): boolean {
|
||||
let range = this.calculateRange()
|
||||
let closestTargetTo = this.world.getClosestTargetTo(this.world.player.position, range);
|
||||
if(closestTargetTo !== undefined && closestTargetTo[1] !== undefined) {
|
||||
let stats = new ProjectileStats()
|
||||
.withPiercings(this.stats.projectilePiercings)
|
||||
.withSize(1)
|
||||
.withDamage(this.getDamage())
|
||||
.withSpeed(this.stats.projectileSpeed);
|
||||
let projectile = HomingProjectile.createHomingProjectile(this.world, this.getPosition(), this.player, closestTargetTo[1]!, stats, 'yellow')
|
||||
this.projectiles.push(projectile)
|
||||
return true
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static generateHomingPistol(world: World, offset?: Vector) {
|
||||
if(!offset) {
|
||||
offset = new Vector(5, 5)
|
||||
}
|
||||
let stats = new WeaponStats()
|
||||
.withProjectileSpeed(3)
|
||||
.withDamage(3)
|
||||
.withShootInterval(50)
|
||||
let pistol = new HomingPistol(world, stats)
|
||||
pistol.offset = offset;
|
||||
pistol.size = 5;
|
||||
pistol.color = 'yellow';
|
||||
return pistol;
|
||||
}
|
||||
}
|
||||
|
||||
export class Pistol extends RangeWeapon {
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
fillDot(this.getPosition(), 1, this.color, ctx)
|
||||
}
|
||||
|
||||
private createProjectile(): boolean {
|
||||
let range = this.calculateRange()
|
||||
let closestTargetTo = this.world.getClosestTargetTo(this.world.player.position, range);
|
||||
if(closestTargetTo !== undefined && closestTargetTo[1] !== undefined) {
|
||||
let stats = new ProjectileStats()
|
||||
.withPiercings(this.stats.projectilePiercings)
|
||||
.withSize(1)
|
||||
.withDamage(this.getDamage())
|
||||
.withSpeed(this.stats.projectileSpeed);
|
||||
let projectile = StraightProjectile.createStraightProjectile(this.world, this.getPosition(), closestTargetTo[1]!.getPosition(), this.player, stats, 'pink')
|
||||
this.projectiles.push(projectile)
|
||||
return true
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static generatePistol(world: World, offset?: Vector) {
|
||||
if(!offset) {
|
||||
offset = new Vector(5, 5)
|
||||
}
|
||||
let stats = new WeaponStats()
|
||||
.withProjectileSpeed(4)
|
||||
.withDamage(4)
|
||||
.withShootInterval(25)
|
||||
let pistol = new Pistol(world, stats)
|
||||
pistol.offset = offset;
|
||||
pistol.size = 5;
|
||||
pistol.color = 'brown';
|
||||
return pistol;
|
||||
}
|
||||
}
|
||||
|
||||
export class SpreadWeapon extends RangeWeapon {
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
fillDot(this.getPosition(), 1, this.color, ctx)
|
||||
}
|
||||
|
||||
private createProjectile(): boolean {
|
||||
let range = this.calculateRange()
|
||||
let closestTargetTo = this.world.getClosestTargetTo(this.world.player.position, range);
|
||||
if(closestTargetTo !== undefined && closestTargetTo[1] !== undefined) {
|
||||
let stats = new ProjectileStats()
|
||||
.withPiercings(this.stats.projectilePiercings)
|
||||
.withSize(1)
|
||||
.withDamage(this.getDamage())
|
||||
.withSpeed(this.stats.projectileSpeed);
|
||||
let targetPosition = closestTargetTo[1]!.getPosition();
|
||||
let weaponPosition = this.getPosition();
|
||||
let mainVector = Vector.createVector(targetPosition, weaponPosition)
|
||||
let mainProjectile = StraightProjectile.createStraightProjectile(this.world, weaponPosition, targetPosition, this.player, stats, 'gray')
|
||||
this.projectiles.push(mainProjectile)
|
||||
let upperVector = mainVector.rotate(toRad(-30))
|
||||
let upperTarget = weaponPosition.add(upperVector.multiply(this.world.maxValue()))
|
||||
let upperProjectile = StraightProjectile.createStraightProjectile(this.world, weaponPosition, upperTarget, this.player, stats, 'gray')
|
||||
this.projectiles.push(upperProjectile)
|
||||
let lowerVector = mainVector.rotate(toRad(30))
|
||||
let lowerTarget = weaponPosition.add(lowerVector.multiply(this.world.maxValue()))
|
||||
let lowerProjectile = StraightProjectile.createStraightProjectile(this.world, weaponPosition, lowerTarget, this.player, stats, 'gray')
|
||||
this.projectiles.push(lowerProjectile)
|
||||
return true
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static generateSpreadWeapon(world: World, offset?: Vector) {
|
||||
if(!offset) {
|
||||
offset = new Vector(5, 5)
|
||||
}
|
||||
let stats = new WeaponStats()
|
||||
.withProjectileSpeed(3)
|
||||
.withDamage(3)
|
||||
.withShootInterval(40)
|
||||
let pistol = new SpreadWeapon(world, stats)
|
||||
pistol.offset = offset;
|
||||
pistol.size = 5;
|
||||
pistol.color = 'gray';
|
||||
return pistol;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class WeaponStats {
|
||||
|
||||
private _weaponRange: number;
|
||||
private _weaponRangeFactor: number;
|
||||
private _projectileSpeed: number;
|
||||
private _projectilePiercings: number;
|
||||
private _damage: number;
|
||||
private _shootInterval: number;
|
||||
|
||||
constructor() {
|
||||
this._weaponRangeFactor = 1
|
||||
this._weaponRange = 50
|
||||
this._projectilePiercings = 0
|
||||
this._projectileSpeed = 100
|
||||
this._damage = 1
|
||||
this._shootInterval = 50
|
||||
}
|
||||
|
||||
increase() {
|
||||
this._weaponRange *= 1.1;
|
||||
this._weaponRangeFactor += 0.05;
|
||||
this._damage *= 1.25;
|
||||
this._shootInterval *= 0.9
|
||||
}
|
||||
|
||||
withWeaponRange(value: number) {
|
||||
this._weaponRange = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
withWeaponRangeFactor(value: number) {
|
||||
this._weaponRangeFactor = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
withProjectileSpeed(value: number) {
|
||||
this._projectileSpeed = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
withShootInterval(value: number) {
|
||||
this._shootInterval = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
withProjectilePiercings(value: number) {
|
||||
this._projectilePiercings = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
withDamage(value: number) {
|
||||
this._damage = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
get weaponRange(): number {
|
||||
return this._weaponRange;
|
||||
}
|
||||
|
||||
get weaponRangeFactor(): number {
|
||||
return this._weaponRangeFactor
|
||||
}
|
||||
|
||||
|
||||
get projectilePiercings(): number {
|
||||
return this._projectilePiercings;
|
||||
}
|
||||
|
||||
get damage(): number {
|
||||
return this._damage;
|
||||
}
|
||||
|
||||
get projectileSpeed(): number {
|
||||
return this._projectileSpeed;
|
||||
}
|
||||
|
||||
get shootInterval(): number {
|
||||
return this._shootInterval;
|
||||
}
|
||||
|
||||
get effectiveWeaponRange(): number {
|
||||
return this._weaponRange * this._weaponRangeFactor
|
||||
}
|
||||
}
|
||||
25
absurd-survivors/tsconfig.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
8
absurd-survivors/vite.config.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
base: './',
|
||||
build: {
|
||||
outDir: '../dist/survivors'
|
||||
},
|
||||
})
|
||||
@@ -28,7 +28,7 @@ var config = {
|
||||
resetTapsDecreaseInterval: 2
|
||||
},
|
||||
general: {
|
||||
fps: 30
|
||||
fps: 60
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
872
bubbles/package-lock.json
generated
Normal file
@@ -0,0 +1,872 @@
|
||||
{
|
||||
"name": "bubbles",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "bubbles",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"canvas-common": "file:../canvas-common"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^5.1.5"
|
||||
}
|
||||
},
|
||||
"../canvas-common": {
|
||||
"version": "1.0.0",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
||||
"integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
|
||||
"integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
|
||||
"integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
|
||||
"integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
|
||||
"integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
|
||||
"integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
|
||||
"integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
|
||||
"integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
|
||||
"integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
|
||||
"integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz",
|
||||
"integrity": "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz",
|
||||
"integrity": "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz",
|
||||
"integrity": "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz",
|
||||
"integrity": "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz",
|
||||
"integrity": "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz",
|
||||
"integrity": "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz",
|
||||
"integrity": "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz",
|
||||
"integrity": "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz",
|
||||
"integrity": "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz",
|
||||
"integrity": "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz",
|
||||
"integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz",
|
||||
"integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz",
|
||||
"integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz",
|
||||
"integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/canvas-common": {
|
||||
"resolved": "../canvas-common",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
||||
"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.21.5",
|
||||
"@esbuild/android-arm": "0.21.5",
|
||||
"@esbuild/android-arm64": "0.21.5",
|
||||
"@esbuild/android-x64": "0.21.5",
|
||||
"@esbuild/darwin-arm64": "0.21.5",
|
||||
"@esbuild/darwin-x64": "0.21.5",
|
||||
"@esbuild/freebsd-arm64": "0.21.5",
|
||||
"@esbuild/freebsd-x64": "0.21.5",
|
||||
"@esbuild/linux-arm": "0.21.5",
|
||||
"@esbuild/linux-arm64": "0.21.5",
|
||||
"@esbuild/linux-ia32": "0.21.5",
|
||||
"@esbuild/linux-loong64": "0.21.5",
|
||||
"@esbuild/linux-mips64el": "0.21.5",
|
||||
"@esbuild/linux-ppc64": "0.21.5",
|
||||
"@esbuild/linux-riscv64": "0.21.5",
|
||||
"@esbuild/linux-s390x": "0.21.5",
|
||||
"@esbuild/linux-x64": "0.21.5",
|
||||
"@esbuild/netbsd-x64": "0.21.5",
|
||||
"@esbuild/openbsd-x64": "0.21.5",
|
||||
"@esbuild/sunos-x64": "0.21.5",
|
||||
"@esbuild/win32-arm64": "0.21.5",
|
||||
"@esbuild/win32-ia32": "0.21.5",
|
||||
"@esbuild/win32-x64": "0.21.5"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz",
|
||||
"integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.8"
|
||||
},
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0",
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.46.2",
|
||||
"@rollup/rollup-android-arm64": "4.46.2",
|
||||
"@rollup/rollup-darwin-arm64": "4.46.2",
|
||||
"@rollup/rollup-darwin-x64": "4.46.2",
|
||||
"@rollup/rollup-freebsd-arm64": "4.46.2",
|
||||
"@rollup/rollup-freebsd-x64": "4.46.2",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.46.2",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.46.2",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.46.2",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.46.2",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-x64-musl": "4.46.2",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.46.2",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.46.2",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.46.2",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.4.19",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz",
|
||||
"integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.21.3",
|
||||
"postcss": "^8.4.43",
|
||||
"rollup": "^4.20.0"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.0.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": "^18.0.0 || >=20.0.0",
|
||||
"less": "*",
|
||||
"lightningcss": "^1.21.0",
|
||||
"sass": "*",
|
||||
"sass-embedded": "*",
|
||||
"stylus": "*",
|
||||
"sugarss": "*",
|
||||
"terser": "^5.4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"less": {
|
||||
"optional": true
|
||||
},
|
||||
"lightningcss": {
|
||||
"optional": true
|
||||
},
|
||||
"sass": {
|
||||
"optional": true
|
||||
},
|
||||
"sass-embedded": {
|
||||
"optional": true
|
||||
},
|
||||
"stylus": {
|
||||
"optional": true
|
||||
},
|
||||
"sugarss": {
|
||||
"optional": true
|
||||
},
|
||||
"terser": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
bubbles/package.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "bubbles",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"canvas-common": "file:../canvas-common"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^5.1.5"
|
||||
}
|
||||
}
|
||||
22
bubbles/src/index.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<!doctype html>
|
||||
<html class="no-js" lang="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>bubbles</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
html, body, div, canvas {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html, body { width:100%; height:100%; }
|
||||
canvas { display:block; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="canvas"></canvas>
|
||||
<script type="module" src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
137
bubbles/src/js/main.js
Normal file
@@ -0,0 +1,137 @@
|
||||
import {
|
||||
createRainbowColors, docReady, pointDistance, randomInteger
|
||||
} from "canvas-common";
|
||||
|
||||
var imageData = {};
|
||||
var ctx = {};
|
||||
var canvas = {};
|
||||
|
||||
|
||||
var config = {
|
||||
size: {
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight
|
||||
},
|
||||
buBbles: {
|
||||
tileSize: 100,
|
||||
growFactorDivider: 5,
|
||||
radiusFactor: 1,
|
||||
bubbleChance: 0.5
|
||||
}
|
||||
};
|
||||
|
||||
var rainbow = createRainbowColors(1/16);
|
||||
// max distance from top left corner
|
||||
var max = Math.sqrt(Math.pow(config.size.width + config.buBbles.tileSize, 2) + Math.pow(config.size.height + config.buBbles.tileSize, 2));
|
||||
var startOffset = (rainbow.length * Math.random()) << 0;
|
||||
|
||||
function getRandomPoint(x, y) {
|
||||
var distance = Math.sqrt(x * x + y * y);
|
||||
var index = ((startOffset + distance / max * 100) << 0) % rainbow.length;
|
||||
var color = rainbow[index];
|
||||
color.a = 255;
|
||||
return {
|
||||
x: x + Math.random() * config.buBbles.tileSize,
|
||||
y: y + Math.random() * config.buBbles.tileSize,
|
||||
factor: Math.random() / config.buBbles.growFactorDivider,
|
||||
radius: Math.random() * config.buBbles.radiusFactor,
|
||||
color: color
|
||||
};
|
||||
}
|
||||
|
||||
function getTilePoints(){
|
||||
var points = [];
|
||||
for(var x = 0; x < config.size.width; x += config.buBbles.tileSize){
|
||||
for(var y = 0; y < config.size.height; y += config.buBbles.tileSize){
|
||||
points.push(getRandomPoint(x, y));
|
||||
}
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
docReady(function () {
|
||||
canvas = document.getElementById('canvas')
|
||||
ctx = canvas.getContext("2d");
|
||||
canvas.width = config.size.width;
|
||||
canvas.height = config.size.height;
|
||||
|
||||
var pointsOfInterest = getTilePoints();
|
||||
removeIntersecting(pointsOfInterest);
|
||||
updateCanvas(pointsOfInterest);
|
||||
});
|
||||
|
||||
function grow(points){
|
||||
for(var i = 0; i < points.length; i++){
|
||||
var currentPoint = points[i];
|
||||
if(!intersectsAnotherPoint(currentPoint, points)){
|
||||
currentPoint.radius += currentPoint.factor;
|
||||
} else if(!currentPoint.spawnedAnother){
|
||||
currentPoint.spawnedAnother = true;
|
||||
currentPoint.radius += currentPoint.factor;
|
||||
addAnotherRandomPoint(points);
|
||||
}
|
||||
}
|
||||
|
||||
if(Math.random() < config.buBbles.bubbleChance){
|
||||
addAnotherRandomPoint(points);
|
||||
}
|
||||
}
|
||||
|
||||
function addAnotherRandomPoint(points){
|
||||
var probablePoint = getRandomPoint(randomInteger(config.size.width), randomInteger(config.size.height));
|
||||
if(!intersectsAnotherPoint(probablePoint, points)){
|
||||
points.push(probablePoint);
|
||||
}
|
||||
}
|
||||
|
||||
function intersectsAnotherPoint(point, points){
|
||||
var intersects = false;
|
||||
points.forEach(function(pointToLookAt){
|
||||
if(intersects) return;
|
||||
var pointDist = pointDistance(point, pointToLookAt);
|
||||
if(pointDist > 0 && pointDist < (point.radius + pointToLookAt.radius)){
|
||||
intersects = true;
|
||||
}
|
||||
});
|
||||
|
||||
return intersects;
|
||||
}
|
||||
|
||||
function updateCanvas(points){
|
||||
ctx.clearRect(0, 0, config.size.width, config.size.height);
|
||||
grow(points);
|
||||
paintPoints(points, function(){
|
||||
requestAnimationFrame(function(){
|
||||
updateCanvas(points);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
function removeIntersecting(points){
|
||||
for(var i = 0; i < points.length; ){
|
||||
if(intersectsAnotherPoint(points[i], points)){
|
||||
points.splice(i, 1);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function paintPoints(points, cb){
|
||||
for(var i = 0; i < points.length; i++){
|
||||
var point = points[i];
|
||||
if(point.radius < 0) continue;
|
||||
ctx.beginPath();
|
||||
ctx.fillStyle = point.color.styleRGB;
|
||||
ctx.arc(point.x, point.y, point.radius, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
}
|
||||
cb();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
24
bubbles/src/js/plugins.js
Normal file
@@ -0,0 +1,24 @@
|
||||
// Avoid `console` errors in browsers that lack a console.
|
||||
(function() {
|
||||
var method;
|
||||
var noop = function () {};
|
||||
var methods = [
|
||||
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
|
||||
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
|
||||
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
|
||||
'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn'
|
||||
];
|
||||
var length = methods.length;
|
||||
var console = (window.console = window.console || {});
|
||||
|
||||
while (length--) {
|
||||
method = methods[length];
|
||||
|
||||
// Only stub undefined methods.
|
||||
if (!console[method]) {
|
||||
console[method] = noop;
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
||||
// Place any jQuery/helper plugins in here.
|
||||
9
bubbles/vite.config.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
base: './',
|
||||
root: 'src',
|
||||
build: {
|
||||
outDir: '../../dist/bubbles'
|
||||
}
|
||||
})
|
||||
@@ -74,6 +74,19 @@ export function downloadCanvas(name, canvas_obj, downloadBtn) {
|
||||
downloadBtn.href = URL.createObjectURL(blob);
|
||||
}
|
||||
|
||||
export function downloadCanvasWithoutButton(name, canvas_obj) {
|
||||
var downloadBtn = document.getElementById('download');
|
||||
downloadBtn.download = name + '_' + new Date().toISOString() + '.png';
|
||||
|
||||
var imageData = canvas_obj.toDataURL({
|
||||
format: 'png',
|
||||
multiplier: 4
|
||||
});
|
||||
var blob = dataURLtoBlob(imageData);
|
||||
downloadBtn.href = URL.createObjectURL(blob);
|
||||
|
||||
}
|
||||
|
||||
export function convertColorToRgbaWithAlphaPlaceholderStyle(color) {
|
||||
color.styleRGBA = 'rgba(%red, %green, %blue, %alpha)'
|
||||
.replace('%red', color.r)
|
||||
@@ -121,6 +134,13 @@ export function randomNumberButAtLeast(range, min) {
|
||||
return (rand < min) ? min : rand;
|
||||
}
|
||||
|
||||
export function randomNumber(n, cur) {
|
||||
var rand = (Math.random() * n) - n / 2;
|
||||
if (cur + rand < 0) return 0;
|
||||
return rand;
|
||||
}
|
||||
|
||||
|
||||
export function getIndexForCoordinate(config, x, y) {
|
||||
return (y * config.size.width + x) * 4;
|
||||
}
|
||||
@@ -142,3 +162,15 @@ export function angleBetweenTwoVectors(vectorA, vectorB){
|
||||
export function dotProduct(vector1, vector2) {
|
||||
return vector1.x * vector2.x + vector1.y * vector2.y;
|
||||
}
|
||||
|
||||
export function randomInteger(n){
|
||||
return (Math.random() * n) << 0
|
||||
}
|
||||
|
||||
export function getCoordinates(config, index) {
|
||||
return {x: index / 4 % config.size.width, y: Math.floor((index / 4 / config.size.width))}
|
||||
}
|
||||
|
||||
export function formatInterval(date1, date2, message) {
|
||||
console.log(message + ((date2 - date1) / 1000));
|
||||
}
|
||||
872
circleBs/package-lock.json
generated
Normal file
@@ -0,0 +1,872 @@
|
||||
{
|
||||
"name": "bubbles",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "bubbles",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"canvas-common": "file:../canvas-common"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^5.1.5"
|
||||
}
|
||||
},
|
||||
"../canvas-common": {
|
||||
"version": "1.0.0",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
||||
"integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
|
||||
"integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
|
||||
"integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
|
||||
"integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
|
||||
"integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
|
||||
"integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
|
||||
"integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
|
||||
"integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
|
||||
"integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
|
||||
"integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz",
|
||||
"integrity": "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz",
|
||||
"integrity": "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz",
|
||||
"integrity": "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz",
|
||||
"integrity": "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz",
|
||||
"integrity": "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz",
|
||||
"integrity": "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz",
|
||||
"integrity": "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz",
|
||||
"integrity": "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz",
|
||||
"integrity": "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz",
|
||||
"integrity": "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz",
|
||||
"integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz",
|
||||
"integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz",
|
||||
"integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz",
|
||||
"integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/canvas-common": {
|
||||
"resolved": "../canvas-common",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
||||
"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.21.5",
|
||||
"@esbuild/android-arm": "0.21.5",
|
||||
"@esbuild/android-arm64": "0.21.5",
|
||||
"@esbuild/android-x64": "0.21.5",
|
||||
"@esbuild/darwin-arm64": "0.21.5",
|
||||
"@esbuild/darwin-x64": "0.21.5",
|
||||
"@esbuild/freebsd-arm64": "0.21.5",
|
||||
"@esbuild/freebsd-x64": "0.21.5",
|
||||
"@esbuild/linux-arm": "0.21.5",
|
||||
"@esbuild/linux-arm64": "0.21.5",
|
||||
"@esbuild/linux-ia32": "0.21.5",
|
||||
"@esbuild/linux-loong64": "0.21.5",
|
||||
"@esbuild/linux-mips64el": "0.21.5",
|
||||
"@esbuild/linux-ppc64": "0.21.5",
|
||||
"@esbuild/linux-riscv64": "0.21.5",
|
||||
"@esbuild/linux-s390x": "0.21.5",
|
||||
"@esbuild/linux-x64": "0.21.5",
|
||||
"@esbuild/netbsd-x64": "0.21.5",
|
||||
"@esbuild/openbsd-x64": "0.21.5",
|
||||
"@esbuild/sunos-x64": "0.21.5",
|
||||
"@esbuild/win32-arm64": "0.21.5",
|
||||
"@esbuild/win32-ia32": "0.21.5",
|
||||
"@esbuild/win32-x64": "0.21.5"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz",
|
||||
"integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.8"
|
||||
},
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0",
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.46.2",
|
||||
"@rollup/rollup-android-arm64": "4.46.2",
|
||||
"@rollup/rollup-darwin-arm64": "4.46.2",
|
||||
"@rollup/rollup-darwin-x64": "4.46.2",
|
||||
"@rollup/rollup-freebsd-arm64": "4.46.2",
|
||||
"@rollup/rollup-freebsd-x64": "4.46.2",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.46.2",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.46.2",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.46.2",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.46.2",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-x64-musl": "4.46.2",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.46.2",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.46.2",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.46.2",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.4.19",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz",
|
||||
"integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.21.3",
|
||||
"postcss": "^8.4.43",
|
||||
"rollup": "^4.20.0"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.0.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": "^18.0.0 || >=20.0.0",
|
||||
"less": "*",
|
||||
"lightningcss": "^1.21.0",
|
||||
"sass": "*",
|
||||
"sass-embedded": "*",
|
||||
"stylus": "*",
|
||||
"sugarss": "*",
|
||||
"terser": "^5.4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"less": {
|
||||
"optional": true
|
||||
},
|
||||
"lightningcss": {
|
||||
"optional": true
|
||||
},
|
||||
"sass": {
|
||||
"optional": true
|
||||
},
|
||||
"sass-embedded": {
|
||||
"optional": true
|
||||
},
|
||||
"stylus": {
|
||||
"optional": true
|
||||
},
|
||||
"sugarss": {
|
||||
"optional": true
|
||||
},
|
||||
"terser": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
circleBs/package.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "circleBs",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"canvas-common": "file:../canvas-common"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^5.1.5"
|
||||
}
|
||||
}
|
||||
36
circleBs/src/index.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<!doctype html>
|
||||
<html class="no-js" lang="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>circleBs</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
html, body, div, canvas {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html, body { width:100%; height:100%; }
|
||||
canvas { display:block; }
|
||||
#clearBtn { left: 0px; }
|
||||
#download { left: 60px; top: 3px; }
|
||||
.controls {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 10px
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content">
|
||||
<canvas id="canvas" ></canvas>
|
||||
<div class="controls">
|
||||
<input class="top" id="clearBtn" type="button" onclick="reset()" value="clear" />
|
||||
<a id="download" class="top" onclick="downloadCanvasCommon('circleBs', canvas)">Download</a>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
85
circleBs/src/js/main.js
Normal file
@@ -0,0 +1,85 @@
|
||||
import {
|
||||
docReady, randomNumber
|
||||
} from "canvas-common";
|
||||
|
||||
|
||||
|
||||
var canvas;
|
||||
var ctx;
|
||||
|
||||
var config = {
|
||||
size: {
|
||||
height: window.innerHeight,
|
||||
width: window.innerWidth
|
||||
},
|
||||
circleBs: {
|
||||
maxAge: 1000
|
||||
}
|
||||
};
|
||||
|
||||
var objects = [];
|
||||
|
||||
function update(obj) {
|
||||
obj.deltaX += randomNumber(2);
|
||||
obj.deltaY += randomNumber(2);
|
||||
obj.x += obj.deltaX;
|
||||
obj.y += obj.deltaY;
|
||||
obj.radius += randomNumber(2, obj.radius);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(obj.x, obj.y, obj.radius, 0, 2 * Math.PI);
|
||||
ctx.strokeStyle = obj.col;
|
||||
ctx.stroke();
|
||||
if (obj.deltaX > obj.radius) obj.deltaX -= Math.random() * 2;
|
||||
if (obj.deltaY > obj.radius) obj.deltaY -= Math.random() * 2;
|
||||
if ((obj.x + obj.radius) > config.size.width || (obj.x - obj.radius) < 0) {
|
||||
obj.deltaX *= -1;
|
||||
}
|
||||
if ((obj.y + obj.radius) > config.size.height || (obj.y - obj.radius) < 0) {
|
||||
obj.deltaY *= -1;
|
||||
}
|
||||
obj.age += 1;
|
||||
if (obj.age < config.circleBs.maxAge) {
|
||||
requestAnimationFrame(function(){
|
||||
update(obj);
|
||||
});
|
||||
//setTimeout(function () {
|
||||
// update(obj);
|
||||
//}, 10)
|
||||
}
|
||||
}
|
||||
|
||||
window.reset = reset;
|
||||
|
||||
function reset() {
|
||||
objects.forEach(function (obj) {
|
||||
obj.age = config.circleBs.maxAge;
|
||||
});
|
||||
objects = [];
|
||||
ctx.clearRect(0, 0, config.size.width, config.size.height);
|
||||
createNewCircle();
|
||||
}
|
||||
|
||||
function createNewCircle() {
|
||||
var obj = {
|
||||
x: Math.random() * config.size.width,
|
||||
y: Math.random() * config.size.height,
|
||||
radius: Math.random() * 20,
|
||||
deltaX: 0,
|
||||
deltaY: 0,
|
||||
age: 0,
|
||||
col: '#' + (~~(Math.random() * 255)).toString(16) + (~~(Math.random() * 255)).toString(16) + (~~(Math.random() * 255)).toString(16)
|
||||
};
|
||||
objects.push(obj);
|
||||
requestAnimationFrame(function(){
|
||||
update(obj);
|
||||
});
|
||||
}
|
||||
docReady(function () {
|
||||
canvas = document.getElementById('canvas')
|
||||
canvas.width = config.size.width;
|
||||
canvas.height = config.size.height;
|
||||
ctx = canvas.getContext("2d");
|
||||
reset();
|
||||
setInterval(createNewCircle, 5000)
|
||||
});
|
||||
24
circleBs/src/js/plugins.js
Normal file
@@ -0,0 +1,24 @@
|
||||
// Avoid `console` errors in browsers that lack a console.
|
||||
(function() {
|
||||
var method;
|
||||
var noop = function () {};
|
||||
var methods = [
|
||||
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
|
||||
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
|
||||
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
|
||||
'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn'
|
||||
];
|
||||
var length = methods.length;
|
||||
var console = (window.console = window.console || {});
|
||||
|
||||
while (length--) {
|
||||
method = methods[length];
|
||||
|
||||
// Only stub undefined methods.
|
||||
if (!console[method]) {
|
||||
console[method] = noop;
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
||||
// Place any jQuery/helper plugins in here.
|
||||
9
circleBs/vite.config.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
base: './',
|
||||
root: 'src',
|
||||
build: {
|
||||
outDir: '../../dist/circleBs'
|
||||
}
|
||||
})
|
||||
272
clusterFilter/package-lock.json
generated
Normal file
@@ -0,0 +1,272 @@
|
||||
{
|
||||
"name": "clusterFilter",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "clusterFilter",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"canvas-common": "file:../canvas-common"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^5.1.5"
|
||||
}
|
||||
},
|
||||
"../canvas-common": {
|
||||
"version": "1.0.0",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz",
|
||||
"integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/canvas-common": {
|
||||
"resolved": "../canvas-common",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
||||
"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.21.5",
|
||||
"@esbuild/android-arm": "0.21.5",
|
||||
"@esbuild/android-arm64": "0.21.5",
|
||||
"@esbuild/android-x64": "0.21.5",
|
||||
"@esbuild/darwin-arm64": "0.21.5",
|
||||
"@esbuild/darwin-x64": "0.21.5",
|
||||
"@esbuild/freebsd-arm64": "0.21.5",
|
||||
"@esbuild/freebsd-x64": "0.21.5",
|
||||
"@esbuild/linux-arm": "0.21.5",
|
||||
"@esbuild/linux-arm64": "0.21.5",
|
||||
"@esbuild/linux-ia32": "0.21.5",
|
||||
"@esbuild/linux-loong64": "0.21.5",
|
||||
"@esbuild/linux-mips64el": "0.21.5",
|
||||
"@esbuild/linux-ppc64": "0.21.5",
|
||||
"@esbuild/linux-riscv64": "0.21.5",
|
||||
"@esbuild/linux-s390x": "0.21.5",
|
||||
"@esbuild/linux-x64": "0.21.5",
|
||||
"@esbuild/netbsd-x64": "0.21.5",
|
||||
"@esbuild/openbsd-x64": "0.21.5",
|
||||
"@esbuild/sunos-x64": "0.21.5",
|
||||
"@esbuild/win32-arm64": "0.21.5",
|
||||
"@esbuild/win32-ia32": "0.21.5",
|
||||
"@esbuild/win32-x64": "0.21.5"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz",
|
||||
"integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.8"
|
||||
},
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0",
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.46.2",
|
||||
"@rollup/rollup-android-arm64": "4.46.2",
|
||||
"@rollup/rollup-darwin-arm64": "4.46.2",
|
||||
"@rollup/rollup-darwin-x64": "4.46.2",
|
||||
"@rollup/rollup-freebsd-arm64": "4.46.2",
|
||||
"@rollup/rollup-freebsd-x64": "4.46.2",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.46.2",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.46.2",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.46.2",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.46.2",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-x64-musl": "4.46.2",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.46.2",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.46.2",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.46.2",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.4.19",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz",
|
||||
"integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.21.3",
|
||||
"postcss": "^8.4.43",
|
||||
"rollup": "^4.20.0"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.0.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": "^18.0.0 || >=20.0.0",
|
||||
"less": "*",
|
||||
"lightningcss": "^1.21.0",
|
||||
"sass": "*",
|
||||
"sass-embedded": "*",
|
||||
"stylus": "*",
|
||||
"sugarss": "*",
|
||||
"terser": "^5.4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"less": {
|
||||
"optional": true
|
||||
},
|
||||
"lightningcss": {
|
||||
"optional": true
|
||||
},
|
||||
"sass": {
|
||||
"optional": true
|
||||
},
|
||||
"sass-embedded": {
|
||||
"optional": true
|
||||
},
|
||||
"stylus": {
|
||||
"optional": true
|
||||
},
|
||||
"sugarss": {
|
||||
"optional": true
|
||||
},
|
||||
"terser": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
clusterFilter/package.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "clusterFilter",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"canvas-common": "file:../canvas-common"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^5.1.5"
|
||||
}
|
||||
}
|
||||
BIN
clusterFilter/src/example.jpg
Normal file
|
After Width: | Height: | Size: 284 KiB |
54
clusterFilter/src/index.html
Normal file
@@ -0,0 +1,54 @@
|
||||
<!doctype html>
|
||||
<html class="no-js" lang="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>clusterFilter</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
html, body, div, canvas {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html, body { width:100%; height:100%; }
|
||||
canvas { display:block; }
|
||||
#clearBtn { left: 0px; }
|
||||
#download { left: 60px; top: 3px; }
|
||||
.controls {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 10px
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="controls">
|
||||
A cluster is a point of color in which the pixels might be concentrated in. <br>
|
||||
<label for="equidistant_cluster">Equally distributed colors (random colors if unchecked)</label>
|
||||
<input type="checkbox" checked="checked" id="equidistant_cluster" onchange="setNewClusterFunction()">
|
||||
<input type="button" onclick="generateClusters()" value="Regenerate image">
|
||||
<br>
|
||||
<select id="fun_select" onchange="setNewFunction()">
|
||||
<option value="1">Every pixel moves to half the distance between it and the cluster</option>
|
||||
<option value="2">Sets the pixels to exactly the cluster color (only the cluster colors)</option>
|
||||
<option value="3">Move the pixels in the direction to the cluster (and maybe over it)</option>
|
||||
</select>
|
||||
<span id="dist_wrapper">
|
||||
<label for="dist_in">Distance to move the pixels</label>
|
||||
<input type="number" id="dist_in" onblur="updateConfig()" min="0">
|
||||
</span>
|
||||
<label for="cluster_in">Amount of clusters (essentially amount of colors, bigger number might crash)</label>
|
||||
<input type="number" id="cluster_in" onblur="updateConfig()" min="0">
|
||||
<br>
|
||||
<label for=img_upload>Change image: (bigger images cause slowdown)</label>
|
||||
<input type="file" onchange="previewFile()" id="img_upload"> <a id="download" onclick="downloadCanvas()">Download</a>
|
||||
<br>
|
||||
</div>
|
||||
<img src="example.jpg" id="src_image">
|
||||
<canvas id="src_canvas" style="display: none"></canvas>
|
||||
<canvas id="final_canvas"></canvas>
|
||||
<script type="module" src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
273
clusterFilter/src/js/main.js
Normal file
@@ -0,0 +1,273 @@
|
||||
import {
|
||||
docReady, getCoordinates, formatInterval, getIndexForCoordinate, downloadCanvasWithoutButton
|
||||
} from "canvas-common";
|
||||
|
||||
|
||||
|
||||
var src_canvas;
|
||||
var final_canvas;
|
||||
var ctx;
|
||||
var final_ctx;
|
||||
var final_imageData;
|
||||
var final_data;
|
||||
var inputFields = {};
|
||||
|
||||
var input_data;
|
||||
|
||||
var config = {
|
||||
size: {
|
||||
width: 640,
|
||||
height: 923
|
||||
},
|
||||
clusterFilter: {
|
||||
dist: 120,
|
||||
fun: halfWayDistance,
|
||||
clusterFun: getEquidistantPoints,
|
||||
clusterAmount: 8,
|
||||
cubeSize: 255
|
||||
}
|
||||
};
|
||||
|
||||
var imageInfo;
|
||||
var clusterCenter;
|
||||
|
||||
function renderImageAndGetData(img, targetContext) {
|
||||
targetContext.drawImage(img, 0, 0);
|
||||
var imgData = targetContext.getImageData(0, 0, config.size.width, config.size.height);
|
||||
return imgData.data;
|
||||
}
|
||||
|
||||
function resetImageInfo(data, copyClusterData) {
|
||||
for (var i = 0; i < data.length; i += 4) {
|
||||
var coor = getCoordinates(config, i);
|
||||
var x = coor.x;
|
||||
var y = coor.y;
|
||||
imageInfo[y][x] = {
|
||||
red: data[i],
|
||||
green: data[i + 1],
|
||||
blue: data[i + 2],
|
||||
alpha: data[i + 3],
|
||||
cluster: copyClusterData ? imageInfo[y][x].cluster : undefined
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function createImageInfo() {
|
||||
var img = document.getElementById('src_image');
|
||||
config.size.width = img.clientWidth;
|
||||
config.size.height = img.clientHeight;
|
||||
if (config.size.width == 0) {
|
||||
config.size.width = 500;
|
||||
}
|
||||
if (config.size.height == 0) {
|
||||
config.size.height = 500;
|
||||
}
|
||||
src_canvas.width = config.size.width;
|
||||
src_canvas.height = config.size.height;
|
||||
final_canvas.width = config.size.width;
|
||||
final_canvas.height = config.size.height;
|
||||
|
||||
imageInfo = new Array(config.size.height);
|
||||
for (var i = 0; i < config.size.height; i++) {
|
||||
imageInfo[i] = new Array(config.size.width);
|
||||
}
|
||||
// draw the image here, because resizing causes the context to loose its imageData (it seems)
|
||||
input_data = renderImageAndGetData(img, ctx);
|
||||
resetImageInfo(input_data, false);
|
||||
}
|
||||
function recreateClusterAndClusterDistance() {
|
||||
var timeBefore = new Date();
|
||||
clusterCenter = config.clusterFilter.clusterFun();
|
||||
createImageInfo();
|
||||
for (var y = 0; y < config.size.height; y++) {
|
||||
for (var x = 0; x < config.size.width; x++) {
|
||||
var colorInfoAtThisPos = imageInfo[y][x];
|
||||
var minDist = Number.MAX_VALUE;
|
||||
var foundCluster = -1;
|
||||
for (var clusterIndex = 0; clusterIndex < config.clusterFilter.clusterAmount; clusterIndex++) {
|
||||
var clusterPoint = clusterCenter[clusterIndex];
|
||||
var dist = Math.sqrt(Math.pow(colorInfoAtThisPos.red - clusterPoint.x, 2) +
|
||||
Math.pow(colorInfoAtThisPos.green - clusterPoint.y, 2) +
|
||||
Math.pow(colorInfoAtThisPos.blue - clusterPoint.z, 2));
|
||||
if (dist < minDist) {
|
||||
minDist = dist;
|
||||
foundCluster = clusterIndex;
|
||||
}
|
||||
}
|
||||
colorInfoAtThisPos.cluster = {clusterIndex: foundCluster, dist: minDist};
|
||||
}
|
||||
}
|
||||
|
||||
var timeAfter = new Date();
|
||||
formatInterval(timeBefore, timeAfter, "cluster distance and imageInfo creation took ...");
|
||||
}
|
||||
|
||||
function halfWayDistance(colorInfoAtThisPos, unused) {
|
||||
colorInfoAtThisPos.red = (colorInfoAtThisPos.red + clusterCenter[colorInfoAtThisPos.cluster.clusterIndex].x) / 2;
|
||||
colorInfoAtThisPos.green = (colorInfoAtThisPos.green + clusterCenter[colorInfoAtThisPos.cluster.clusterIndex].y) / 2;
|
||||
colorInfoAtThisPos.blue = (colorInfoAtThisPos.blue + clusterCenter[colorInfoAtThisPos.cluster.clusterIndex].z) / 2;
|
||||
}
|
||||
|
||||
function exactlyCluster(colorInfoAtThisPos, unused) {
|
||||
colorInfoAtThisPos.red = clusterCenter[colorInfoAtThisPos.cluster.clusterIndex].x;
|
||||
colorInfoAtThisPos.green = clusterCenter[colorInfoAtThisPos.cluster.clusterIndex].y;
|
||||
colorInfoAtThisPos.blue = clusterCenter[colorInfoAtThisPos.cluster.clusterIndex].z;
|
||||
}
|
||||
|
||||
function addDistanceToPoint(colorInfoAtThisPos, dist) {
|
||||
var vect = {
|
||||
x: colorInfoAtThisPos.red - clusterCenter[colorInfoAtThisPos.cluster.clusterIndex].x,
|
||||
y: colorInfoAtThisPos.green - clusterCenter[colorInfoAtThisPos.cluster.clusterIndex].y,
|
||||
z: colorInfoAtThisPos.blue - clusterCenter[colorInfoAtThisPos.cluster.clusterIndex].z
|
||||
};
|
||||
vect.x /= dist;
|
||||
vect.y /= dist;
|
||||
vect.z /= dist;
|
||||
|
||||
colorInfoAtThisPos.red += vect.x * config.clusterFilter.dist;
|
||||
colorInfoAtThisPos.green += vect.y * config.clusterFilter.dist;
|
||||
colorInfoAtThisPos.blue += vect.z * config.clusterFilter.dist;
|
||||
}
|
||||
|
||||
function getEquidistantPoints() {
|
||||
var clusterCenter = [];
|
||||
var increment = config.clusterFilter.cubeSize / Math.cbrt(config.clusterFilter.clusterAmount);
|
||||
for (var x = 0; x < config.clusterFilter.cubeSize; x += increment) {
|
||||
for (var y = 0; y < config.clusterFilter.cubeSize; y += increment) {
|
||||
for (var z = 0; z < config.clusterFilter.cubeSize; z += increment) {
|
||||
clusterCenter.push({x: x, y: y, z: z});
|
||||
}
|
||||
}
|
||||
}
|
||||
return clusterCenter;
|
||||
}
|
||||
function getRandomClusters() {
|
||||
var clusterCenter = [];
|
||||
for (var i = 0; i < config.clusterFilter.clusterAmount; i++) {
|
||||
clusterCenter.push({
|
||||
x: Math.random() * config.clusterFilter.cubeSize,
|
||||
y: Math.random() * config.clusterFilter.cubeSize,
|
||||
z: Math.random() * config.clusterFilter.cubeSize
|
||||
});
|
||||
}
|
||||
return clusterCenter;
|
||||
}
|
||||
function applyClusterFilter() {
|
||||
var timeBefore = new Date();
|
||||
resetImageInfo(input_data, true);
|
||||
final_imageData = final_ctx.createImageData(config.size.width, config.size.height);
|
||||
final_data = final_imageData.data;
|
||||
for (var y = 0; y < config.size.height; y++) {
|
||||
for (var x = 0; x < config.size.width; x++) {
|
||||
var colorInfoAtThisPos = imageInfo[y][x];
|
||||
config.clusterFilter.fun(colorInfoAtThisPos, colorInfoAtThisPos.cluster.dist);
|
||||
}
|
||||
}
|
||||
|
||||
for (var y = 0; y < config.size.height; y++) {
|
||||
for (var x = 0; x < config.size.width; x++) {
|
||||
var colorInfoAtThisPos = imageInfo[y][x];
|
||||
var index = getIndexForCoordinate(config, x, y);
|
||||
final_data[index] = colorInfoAtThisPos.red;
|
||||
final_data[index + 1] = colorInfoAtThisPos.green;
|
||||
final_data[index + 2] = colorInfoAtThisPos.blue;
|
||||
final_data[index + 3] = colorInfoAtThisPos.alpha;
|
||||
}
|
||||
}
|
||||
|
||||
final_ctx.putImageData(final_imageData, 0, 0);
|
||||
var timeAfter = new Date();
|
||||
formatInterval(timeBefore, timeAfter, "rendering took...");
|
||||
}
|
||||
|
||||
docReady(function () {
|
||||
src_canvas = document.getElementById('src_canvas');
|
||||
final_canvas = document.getElementById('final_canvas');
|
||||
ctx = src_canvas.getContext("2d");
|
||||
final_ctx = final_canvas.getContext("2d");
|
||||
inputFields['clusterAmount'] = document.getElementById('cluster_in');
|
||||
inputFields['clusterAmount'].value = config.clusterFilter.clusterAmount;
|
||||
inputFields['distance'] = document.getElementById('dist_in');
|
||||
inputFields['distance'].value = config.clusterFilter.dist;
|
||||
inputFields['distanceWrapper'] = document.getElementById('dist_wrapper');
|
||||
inputFields['distanceWrapper'].display = 'none';
|
||||
var newImg = new Image();
|
||||
newImg.src = "example.jpg";
|
||||
newImg.id = 'src_image';
|
||||
newImg.onload = function () {
|
||||
createImageInfo();
|
||||
recreateClusterAndClusterDistance();
|
||||
applyClusterFilter();
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
||||
window.setNewFunction = setNewFunction;
|
||||
window.setNewClusterFunction = setNewClusterFunction;
|
||||
window.downloadCanvas = downloadCanvasClusterFilter;
|
||||
window.previewFile = previewFile;
|
||||
window.updateConfig = updateConfig;
|
||||
window.generateClusters = generateClusters;
|
||||
|
||||
function downloadCanvasClusterFilter() {
|
||||
downloadCanvasWithoutButton('clusterFilter', final_canvas);
|
||||
}
|
||||
|
||||
|
||||
function setNewFunction() {
|
||||
var selectedWAy = document.getElementById('fun_select').value;
|
||||
if (selectedWAy == 1) {
|
||||
config.clusterFilter.fun = halfWayDistance;
|
||||
inputFields['distanceWrapper'].display = 'none';
|
||||
} else if (selectedWAy == 2) {
|
||||
config.clusterFilter.fun = exactlyCluster;
|
||||
inputFields['distanceWrapper'].display = 'none';
|
||||
} else {
|
||||
config.clusterFilter.fun = addDistanceToPoint;
|
||||
inputFields['distanceWrapper'].display = 'none';
|
||||
}
|
||||
applyClusterFilter();
|
||||
}
|
||||
|
||||
function setNewClusterFunction() {
|
||||
if (document.getElementById('equidistant_cluster').checked) {
|
||||
config.clusterFilter.clusterFun = getEquidistantPoints;
|
||||
} else {
|
||||
config.clusterFilter.clusterFun = getRandomClusters;
|
||||
}
|
||||
recreateClusterAndClusterDistance();
|
||||
applyClusterFilter();
|
||||
}
|
||||
|
||||
function generateClusters() {
|
||||
recreateClusterAndClusterDistance();
|
||||
applyClusterFilter();
|
||||
}
|
||||
|
||||
function updateConfig() {
|
||||
config.clusterFilter.dist = inputFields['distance'].value;
|
||||
var newClusterAmount = inputFields['clusterAmount'].value;
|
||||
if (config.clusterFilter.clusterAmount != newClusterAmount) {
|
||||
config.clusterFilter.clusterAmount = newClusterAmount;
|
||||
recreateClusterAndClusterDistance();
|
||||
}
|
||||
applyClusterFilter();
|
||||
}
|
||||
|
||||
function previewFile() {
|
||||
var preview = document.getElementById('src_image');
|
||||
var file = document.getElementById('img_upload').files[0]; //sames as here
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = function () {
|
||||
preview.src = reader.result;
|
||||
recreateClusterAndClusterDistance();
|
||||
applyClusterFilter();
|
||||
};
|
||||
|
||||
if (file) {
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
preview.src = "";
|
||||
}
|
||||
}
|
||||
24
clusterFilter/src/js/plugins.js
Normal file
@@ -0,0 +1,24 @@
|
||||
// Avoid `console` errors in browsers that lack a console.
|
||||
(function() {
|
||||
var method;
|
||||
var noop = function () {};
|
||||
var methods = [
|
||||
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
|
||||
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
|
||||
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
|
||||
'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn'
|
||||
];
|
||||
var length = methods.length;
|
||||
var console = (window.console = window.console || {});
|
||||
|
||||
while (length--) {
|
||||
method = methods[length];
|
||||
|
||||
// Only stub undefined methods.
|
||||
if (!console[method]) {
|
||||
console[method] = noop;
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
||||
// Place any jQuery/helper plugins in here.
|
||||
9
clusterFilter/vite.config.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
base: './',
|
||||
root: 'src',
|
||||
build: {
|
||||
outDir: '../../dist/clusterFilter'
|
||||
}
|
||||
})
|
||||
872
collatzConjecture/package-lock.json
generated
Normal file
@@ -0,0 +1,872 @@
|
||||
{
|
||||
"name": "collatzConjecture",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "collatzConjecture",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"canvas-common": "file:../canvas-common"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^5.1.5"
|
||||
}
|
||||
},
|
||||
"../canvas-common": {
|
||||
"version": "1.0.0",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
||||
"integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
|
||||
"integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
|
||||
"integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
|
||||
"integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
|
||||
"integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
|
||||
"integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
|
||||
"integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
|
||||
"integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
|
||||
"integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
|
||||
"integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz",
|
||||
"integrity": "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz",
|
||||
"integrity": "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz",
|
||||
"integrity": "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz",
|
||||
"integrity": "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz",
|
||||
"integrity": "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz",
|
||||
"integrity": "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz",
|
||||
"integrity": "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz",
|
||||
"integrity": "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz",
|
||||
"integrity": "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz",
|
||||
"integrity": "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz",
|
||||
"integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz",
|
||||
"integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz",
|
||||
"integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz",
|
||||
"integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/canvas-common": {
|
||||
"resolved": "../canvas-common",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
||||
"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.21.5",
|
||||
"@esbuild/android-arm": "0.21.5",
|
||||
"@esbuild/android-arm64": "0.21.5",
|
||||
"@esbuild/android-x64": "0.21.5",
|
||||
"@esbuild/darwin-arm64": "0.21.5",
|
||||
"@esbuild/darwin-x64": "0.21.5",
|
||||
"@esbuild/freebsd-arm64": "0.21.5",
|
||||
"@esbuild/freebsd-x64": "0.21.5",
|
||||
"@esbuild/linux-arm": "0.21.5",
|
||||
"@esbuild/linux-arm64": "0.21.5",
|
||||
"@esbuild/linux-ia32": "0.21.5",
|
||||
"@esbuild/linux-loong64": "0.21.5",
|
||||
"@esbuild/linux-mips64el": "0.21.5",
|
||||
"@esbuild/linux-ppc64": "0.21.5",
|
||||
"@esbuild/linux-riscv64": "0.21.5",
|
||||
"@esbuild/linux-s390x": "0.21.5",
|
||||
"@esbuild/linux-x64": "0.21.5",
|
||||
"@esbuild/netbsd-x64": "0.21.5",
|
||||
"@esbuild/openbsd-x64": "0.21.5",
|
||||
"@esbuild/sunos-x64": "0.21.5",
|
||||
"@esbuild/win32-arm64": "0.21.5",
|
||||
"@esbuild/win32-ia32": "0.21.5",
|
||||
"@esbuild/win32-x64": "0.21.5"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz",
|
||||
"integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.8"
|
||||
},
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0",
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.46.2",
|
||||
"@rollup/rollup-android-arm64": "4.46.2",
|
||||
"@rollup/rollup-darwin-arm64": "4.46.2",
|
||||
"@rollup/rollup-darwin-x64": "4.46.2",
|
||||
"@rollup/rollup-freebsd-arm64": "4.46.2",
|
||||
"@rollup/rollup-freebsd-x64": "4.46.2",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.46.2",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.46.2",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.46.2",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.46.2",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-x64-musl": "4.46.2",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.46.2",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.46.2",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.46.2",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.4.19",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz",
|
||||
"integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.21.3",
|
||||
"postcss": "^8.4.43",
|
||||
"rollup": "^4.20.0"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.0.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": "^18.0.0 || >=20.0.0",
|
||||
"less": "*",
|
||||
"lightningcss": "^1.21.0",
|
||||
"sass": "*",
|
||||
"sass-embedded": "*",
|
||||
"stylus": "*",
|
||||
"sugarss": "*",
|
||||
"terser": "^5.4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"less": {
|
||||
"optional": true
|
||||
},
|
||||
"lightningcss": {
|
||||
"optional": true
|
||||
},
|
||||
"sass": {
|
||||
"optional": true
|
||||
},
|
||||
"sass-embedded": {
|
||||
"optional": true
|
||||
},
|
||||
"stylus": {
|
||||
"optional": true
|
||||
},
|
||||
"sugarss": {
|
||||
"optional": true
|
||||
},
|
||||
"terser": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
collatzConjecture/package.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "collatzConjecture",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"canvas-common": "file:../canvas-common"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^5.1.5"
|
||||
}
|
||||
}
|
||||
60
collatzConjecture/src/index.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<!doctype html>
|
||||
<html class="no-js" lang="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>collatzConjecture</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
html, body, div, canvas {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html, body { width:100%; height:100%; }
|
||||
canvas { display:block; }
|
||||
/*.controls {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 10px
|
||||
}*/
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<label for="heightChange">Size of tree</label>
|
||||
<input type="range" value="25" min="1" max="50" id="heightChange" oninput="setNewHeightChange(this.value)">
|
||||
<label for="spread">Spread</label>
|
||||
<input type="range" value="5" min="1" id="spread" oninput="setNewSpread(this.value)" max="30">
|
||||
|
||||
|
||||
<label for="firstNumber">First number</label>
|
||||
<input type="range" value="2" min="1" max="50" id="firstNumber" oninput="setNewFirstNumber(this.value)">
|
||||
<label for="secondNumber">Second number</label>
|
||||
<input type="range" value="3" min="1" id="secondNumber" oninput="setNewSecondNumber(this.value)" max="50">
|
||||
|
||||
<label for="size">Canvas Size:</label>
|
||||
<input type="number" id="size" max="10000" onblur="updateCanvasConfig(this.value)">
|
||||
<input type="button" value="reinitialize colors" onclick="generateColors(); updateCanvas()">
|
||||
<br>
|
||||
Explanation of first and second number:
|
||||
The typical conjecture is in the form of: 3n + 1 with the property of dividing by two if odd etc.... (Explanation <a href="https://en.wikipedia.org/wiki/Collatz_conjecture">here</a>). <br> The 'firstNumber' is the 2 in the formula and the 'secondNumber' the 3.
|
||||
Beware of ... interesting outcomes as this can cause the created tree to become very large... often too much for the browser.
|
||||
<br>
|
||||
<span>
|
||||
Height:
|
||||
<span id="heightValue"></span>
|
||||
Spread:
|
||||
<span id="spreadValue"></span>
|
||||
Firstnumber:
|
||||
<span id="firstValue"></span>
|
||||
Secondnumber:
|
||||
<span id="secondValue"></span>
|
||||
</span>
|
||||
<br>
|
||||
<a id="download" onclick="downloadCanvasCommon()">Download</a>
|
||||
<br>
|
||||
<canvas id="canvas"></canvas>
|
||||
|
||||
<script type="module" src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
242
collatzConjecture/src/js/main.js
Normal file
@@ -0,0 +1,242 @@
|
||||
import {
|
||||
docReady, d2h, toRad, downloadCanvasWithoutButton
|
||||
} from "canvas-common";
|
||||
|
||||
|
||||
|
||||
var ctx = {};
|
||||
var canvas = {};
|
||||
|
||||
var used = {};
|
||||
var colors = [];
|
||||
var collatzTree;
|
||||
|
||||
var heightChange;
|
||||
var sizeInput;
|
||||
var spreadInput;
|
||||
var heightValue;
|
||||
var spreadValue;
|
||||
var firstValue;
|
||||
var secondValue;
|
||||
|
||||
var startCol = {r: 0, g: 0, b: 0};
|
||||
var finalCol = {r: 0, g: 0, b: 0};
|
||||
var colorPoints = [];
|
||||
|
||||
function setToPinkishColors() {
|
||||
colorPoints.push({r: 38, g: 17, b: 43});
|
||||
colorPoints.push({r: 86, g: 37, b: 81});
|
||||
colorPoints.push({r: 132, g: 60, b: 107});
|
||||
colorPoints.push({r: 171, g: 88, b: 126});
|
||||
colorPoints.push({r: 202, g: 122, b: 142});
|
||||
colorPoints.push({r: 224, g: 159, b: 161});
|
||||
colorPoints.push({r: 238, g: 198, b: 189});
|
||||
colorPoints.push({r: 249, g: 237, b: 229});
|
||||
finalCol = colorPoints[colorPoints.length - 1];
|
||||
}
|
||||
|
||||
|
||||
var config = {
|
||||
size: {
|
||||
size: 1500
|
||||
},
|
||||
conjectureConfig: {
|
||||
firstNumber: 2,
|
||||
secondNumber: 3,
|
||||
maxDepth: 30,
|
||||
heightChange: 25,
|
||||
dirChange: 10
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function buildStructure(input, depth) {
|
||||
if (depth > config.conjectureConfig.maxDepth) return undefined;
|
||||
if (input in used) {
|
||||
return undefined
|
||||
}
|
||||
depth++;
|
||||
used[input] = 1;
|
||||
var element = {};
|
||||
element.num = input;
|
||||
var child1 = buildStructure(input * config.conjectureConfig.firstNumber, depth);
|
||||
var child2 = undefined;
|
||||
var inputSmaller = input - 1;
|
||||
var probableNumber = (inputSmaller) / config.conjectureConfig.secondNumber;
|
||||
if ((inputSmaller) % config.conjectureConfig.secondNumber == 0 && (probableNumber % config.conjectureConfig.firstNumber != 0)) {
|
||||
child2 = buildStructure(probableNumber, depth);
|
||||
}
|
||||
element.child1 = child1;
|
||||
element.child2 = child2;
|
||||
return element;
|
||||
}
|
||||
|
||||
function setNewHeightChange(newValue) {
|
||||
config.conjectureConfig.heightChange = parseInt(newValue);
|
||||
heightValue.innerText = config.conjectureConfig.heightChange;
|
||||
updateCanvas();
|
||||
}
|
||||
|
||||
function setNewSpread(newValue) {
|
||||
config.conjectureConfig.dirChange = parseInt(newValue);
|
||||
spreadValue.innerText = config.conjectureConfig.dirChange;
|
||||
updateCanvas();
|
||||
}
|
||||
|
||||
// TODO fix with different amount of colors
|
||||
function drawElement(input, dir, parentPos, depth) {
|
||||
if (depth >= config.conjectureConfig.maxDepth || input in used) return;
|
||||
//console.log('__________________')
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(parentPos.x, parentPos.y);
|
||||
var numberOfStepsEachColor = Math.round(config.conjectureConfig.maxDepth / colorPoints.length);
|
||||
// often... this returns a higher color, but the ratio is still in above 0.5, so the color changes drastically
|
||||
var whereToMoveColorWise = (~~((depth) / config.conjectureConfig.maxDepth * 0.995 * colorPoints.length) + 1);
|
||||
var ratio = (depth % (numberOfStepsEachColor)) / ((numberOfStepsEachColor));
|
||||
// sometimes a color to high is chosen with a high ratio, this causes the color change to be wrong (and very drastic)
|
||||
// we need to go a step back
|
||||
if (ratio >= 1) {
|
||||
whereToMoveColorWise--;
|
||||
}
|
||||
else if (ratio > 0.5) {
|
||||
whereToMoveColorWise = (~~((depth - 1) / config.conjectureConfig.maxDepth * 0.995 * colorPoints.length) + 1);
|
||||
}
|
||||
|
||||
var targetColor = colorPoints[whereToMoveColorWise];
|
||||
if (whereToMoveColorWise == colorPoints.length) {
|
||||
targetColor = finalCol;
|
||||
}
|
||||
var whereWeComeColorWise = whereToMoveColorWise - 1;
|
||||
//console.log(whereWeComeColorWise + '_' + whereToMoveColorWise)
|
||||
//console.log(depth + '_' + numberOfStepsEachColor)
|
||||
//console.log(ratio + '_' + depth / config.conjectureConfig.maxDepth)
|
||||
|
||||
var baseColor = colorPoints[whereWeComeColorWise];
|
||||
var newColor = {
|
||||
r: targetColor.r * ratio + baseColor.r * (1 - ratio),
|
||||
g: targetColor.g * ratio + baseColor.g * (1 - ratio),
|
||||
b: targetColor.b * ratio + baseColor.b * (1 - ratio)
|
||||
};
|
||||
ctx.strokeStyle = '#' + d2h(~~newColor.r) + d2h(~~newColor.g) + d2h(~~newColor.b);
|
||||
var newXOffset = config.conjectureConfig.heightChange * Math.cos(toRad(dir));
|
||||
//console.log(ctx.strokeStyle)
|
||||
//console.log(newColor)
|
||||
//console.log(baseColor)
|
||||
//console.log(targetColor)
|
||||
var newYOffset = config.conjectureConfig.heightChange * Math.sin(toRad(dir));
|
||||
//ctx.fillText((ctx.strokeStyle) + ' ', parentPos.x, parentPos.y);
|
||||
ctx.lineTo(parentPos.x + newXOffset, parentPos.y + newYOffset);
|
||||
ctx.stroke();
|
||||
// experiment to use two parallel lines represented in the video, doesn't work that well, because the line can cross the other line and then... stuff happens
|
||||
// also lines overlay each other
|
||||
//ctx.strokeStyle = colors[depth + 1];
|
||||
//ctx.moveTo(parentPos.x - Math.cos(toRad(90 - dir)) * config.width / 2, parentPos.y - Math.sin(toRad(90 - dir)) * config.width / 2);
|
||||
//ctx.lineTo(parentPos.x + config.heightChange * Math.cos(toRad(dir)) - Math.cos(toRad(90 - dir)) * config.width / 2,
|
||||
// parentPos.y + config.heightChange * Math.sin(toRad(dir)) - Math.sin(toRad(90 - dir)) * config.width / 2);
|
||||
//
|
||||
//ctx.moveTo(parentPos.x + Math.cos(toRad(90 - dir)) * config.width / 2, parentPos.y + Math.sin(toRad(90 - dir)) * config.width / 2);
|
||||
//ctx.lineTo(parentPos.x + config.heightChange * Math.cos(toRad(dir)) + Math.cos(toRad(90 - dir)) * config.width / 2,
|
||||
// parentPos.y + config.heightChange * Math.sin(toRad(dir)) + Math.sin(toRad(90 - dir)) * config.width / 2);
|
||||
//ctx.stroke();
|
||||
var newParentPos = {
|
||||
x: parentPos.x + newXOffset,
|
||||
y: parentPos.y + newYOffset
|
||||
};
|
||||
depth++;
|
||||
used[input] = 1;
|
||||
drawElement(input * config.conjectureConfig.firstNumber, dir + config.conjectureConfig.dirChange, newParentPos, depth);
|
||||
var inputSmaller = input - 1;
|
||||
var probableNumber = (inputSmaller) / config.conjectureConfig.secondNumber;
|
||||
if ((inputSmaller) % config.conjectureConfig.secondNumber == 0 && (probableNumber % config.conjectureConfig.firstNumber != 0)) {
|
||||
drawElement(probableNumber, dir - config.conjectureConfig.dirChange, newParentPos, depth);
|
||||
}
|
||||
else {
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
function generateColors() {
|
||||
colors = [];
|
||||
colorPoints = [];
|
||||
colorPoints.push(startCol);
|
||||
var maxInc = (255 / config.conjectureConfig.maxDepth);
|
||||
for (var i = 0; i < 3; i++) {
|
||||
var red = ~~(Math.random() * 255);
|
||||
var green = ~~(Math.random() * 255);
|
||||
var blue = ~~(Math.random() * 255);
|
||||
//colors.push('#' + (red).toString(16) + (green).toString(16) + (blue).toString(16));
|
||||
colorPoints.push({r: red, g: green, b: blue});
|
||||
}
|
||||
}
|
||||
|
||||
function updateCanvasConfig(newValue) {
|
||||
config.size.size = parseInt(newValue);
|
||||
initCanvas();
|
||||
updateCanvas();
|
||||
}
|
||||
|
||||
function updateCanvas() {
|
||||
used = {};
|
||||
ctx.clearRect(0, 0, config.size.size, config.size.size);
|
||||
drawElement(1, -180, config.size, 0);
|
||||
}
|
||||
|
||||
function setNewFirstNumber(newVal) {
|
||||
config.conjectureConfig.firstNumber = parseInt(newVal);
|
||||
firstValue.innerText = config.conjectureConfig.firstNumber;
|
||||
updateCanvas();
|
||||
}
|
||||
|
||||
function setNewSecondNumber(newVal) {
|
||||
config.conjectureConfig.secondNumber = parseInt(newVal);
|
||||
secondValue.innerText = config.conjectureConfig.secondNumber;
|
||||
updateCanvas();
|
||||
}
|
||||
|
||||
function initCanvas() {
|
||||
ctx = canvas.getContext("2d");
|
||||
canvas.height = config.size.size;
|
||||
canvas.width = config.size.size;
|
||||
config.size.x = config.size.size / 2;
|
||||
config.size.y = config.size.size / 2;
|
||||
}
|
||||
docReady(function () {
|
||||
canvas = document.getElementById('canvas');
|
||||
initCanvas();
|
||||
|
||||
ctx.font = "8px Verdana";
|
||||
ctx.lineWidth = 1;
|
||||
sizeInput = document.getElementById('size');
|
||||
heightChange = document.getElementById('heightChange');
|
||||
spreadInput = document.getElementById('spread');
|
||||
|
||||
heightValue = document.getElementById('heightValue');
|
||||
heightValue.innerText = config.conjectureConfig.heightChange;
|
||||
spreadValue = document.getElementById('spreadValue');
|
||||
spreadValue.innerText = config.conjectureConfig.dirChange;
|
||||
firstValue = document.getElementById('firstValue');
|
||||
firstValue.innerText = config.conjectureConfig.firstNumber;
|
||||
secondValue = document.getElementById('secondValue');
|
||||
secondValue.innerText = config.conjectureConfig.secondNumber;
|
||||
|
||||
sizeInput.value = config.size.size;
|
||||
spreadInput.value =config.conjectureConfig.dirChange;
|
||||
heightChange.value = config.conjectureConfig.heightChange;
|
||||
setToPinkishColors();
|
||||
//generateColors();
|
||||
drawElement(1, -180, config.size, 0);
|
||||
//initStructure();
|
||||
});
|
||||
|
||||
function downloadCanvasCollatz() {
|
||||
downloadCanvasWithoutButton('collatzConjecture', canvas);
|
||||
}
|
||||
|
||||
window.setNewHeightChange = setNewHeightChange;
|
||||
window.setNewSpread = setNewSpread;
|
||||
window.setNewFirstNumber = setNewFirstNumber;
|
||||
window.setNewSecondNumber = setNewSecondNumber;
|
||||
window.updateCanvasConfig = updateCanvasConfig;
|
||||
window.generateColors = generateColors;
|
||||
window.updateCanvas = updateCanvas;
|
||||
window.downloadCanvasCommon = downloadCanvasCollatz;
|
||||
24
collatzConjecture/src/js/plugins.js
Normal file
@@ -0,0 +1,24 @@
|
||||
// Avoid `console` errors in browsers that lack a console.
|
||||
(function() {
|
||||
var method;
|
||||
var noop = function () {};
|
||||
var methods = [
|
||||
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
|
||||
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
|
||||
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
|
||||
'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn'
|
||||
];
|
||||
var length = methods.length;
|
||||
var console = (window.console = window.console || {});
|
||||
|
||||
while (length--) {
|
||||
method = methods[length];
|
||||
|
||||
// Only stub undefined methods.
|
||||
if (!console[method]) {
|
||||
console[method] = noop;
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
||||
// Place any jQuery/helper plugins in here.
|
||||
9
collatzConjecture/vite.config.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
base: './',
|
||||
root: 'src',
|
||||
build: {
|
||||
outDir: '../../dist/collatzConjecture'
|
||||
}
|
||||
})
|
||||
872
dotLines/package-lock.json
generated
Normal file
@@ -0,0 +1,872 @@
|
||||
{
|
||||
"name": "dotLines",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "dotLines",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"canvas-common": "file:../canvas-common"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^5.1.5"
|
||||
}
|
||||
},
|
||||
"../canvas-common": {
|
||||
"version": "1.0.0",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
||||
"integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
|
||||
"integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
|
||||
"integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
|
||||
"integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
|
||||
"integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
|
||||
"integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
|
||||
"integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
|
||||
"integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
|
||||
"integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
|
||||
"integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz",
|
||||
"integrity": "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz",
|
||||
"integrity": "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz",
|
||||
"integrity": "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz",
|
||||
"integrity": "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz",
|
||||
"integrity": "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz",
|
||||
"integrity": "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz",
|
||||
"integrity": "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz",
|
||||
"integrity": "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz",
|
||||
"integrity": "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz",
|
||||
"integrity": "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz",
|
||||
"integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz",
|
||||
"integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz",
|
||||
"integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz",
|
||||
"integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz",
|
||||
"integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/canvas-common": {
|
||||
"resolved": "../canvas-common",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
||||
"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.21.5",
|
||||
"@esbuild/android-arm": "0.21.5",
|
||||
"@esbuild/android-arm64": "0.21.5",
|
||||
"@esbuild/android-x64": "0.21.5",
|
||||
"@esbuild/darwin-arm64": "0.21.5",
|
||||
"@esbuild/darwin-x64": "0.21.5",
|
||||
"@esbuild/freebsd-arm64": "0.21.5",
|
||||
"@esbuild/freebsd-x64": "0.21.5",
|
||||
"@esbuild/linux-arm": "0.21.5",
|
||||
"@esbuild/linux-arm64": "0.21.5",
|
||||
"@esbuild/linux-ia32": "0.21.5",
|
||||
"@esbuild/linux-loong64": "0.21.5",
|
||||
"@esbuild/linux-mips64el": "0.21.5",
|
||||
"@esbuild/linux-ppc64": "0.21.5",
|
||||
"@esbuild/linux-riscv64": "0.21.5",
|
||||
"@esbuild/linux-s390x": "0.21.5",
|
||||
"@esbuild/linux-x64": "0.21.5",
|
||||
"@esbuild/netbsd-x64": "0.21.5",
|
||||
"@esbuild/openbsd-x64": "0.21.5",
|
||||
"@esbuild/sunos-x64": "0.21.5",
|
||||
"@esbuild/win32-arm64": "0.21.5",
|
||||
"@esbuild/win32-ia32": "0.21.5",
|
||||
"@esbuild/win32-x64": "0.21.5"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.46.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz",
|
||||
"integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.8"
|
||||
},
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0",
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.46.2",
|
||||
"@rollup/rollup-android-arm64": "4.46.2",
|
||||
"@rollup/rollup-darwin-arm64": "4.46.2",
|
||||
"@rollup/rollup-darwin-x64": "4.46.2",
|
||||
"@rollup/rollup-freebsd-arm64": "4.46.2",
|
||||
"@rollup/rollup-freebsd-x64": "4.46.2",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.46.2",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.46.2",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.46.2",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.46.2",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.46.2",
|
||||
"@rollup/rollup-linux-x64-musl": "4.46.2",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.46.2",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.46.2",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.46.2",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.4.19",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz",
|
||||
"integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.21.3",
|
||||
"postcss": "^8.4.43",
|
||||
"rollup": "^4.20.0"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.0.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": "^18.0.0 || >=20.0.0",
|
||||
"less": "*",
|
||||
"lightningcss": "^1.21.0",
|
||||
"sass": "*",
|
||||
"sass-embedded": "*",
|
||||
"stylus": "*",
|
||||
"sugarss": "*",
|
||||
"terser": "^5.4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"less": {
|
||||
"optional": true
|
||||
},
|
||||
"lightningcss": {
|
||||
"optional": true
|
||||
},
|
||||
"sass": {
|
||||
"optional": true
|
||||
},
|
||||
"sass-embedded": {
|
||||
"optional": true
|
||||
},
|
||||
"stylus": {
|
||||
"optional": true
|
||||
},
|
||||
"sugarss": {
|
||||
"optional": true
|
||||
},
|
||||
"terser": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
dotLines/package.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "dotLines",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"canvas-common": "file:../canvas-common"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^5.1.5"
|
||||
}
|
||||
}
|
||||
47
dotLines/src/index.html
Normal file
@@ -0,0 +1,47 @@
|
||||
<!doctype html>
|
||||
<html class="no-js" lang="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>dotLines</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
html, body, div, canvas {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html, body { width:100%; height:100%; }
|
||||
canvas { display:block; }
|
||||
#pauseBtn {
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
#showAllBtn {
|
||||
left: 60px;
|
||||
}
|
||||
|
||||
#download {
|
||||
left: 150px;
|
||||
top: 3px;
|
||||
}
|
||||
.controls {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 10px
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content">
|
||||
<canvas id="canvas" ></canvas>
|
||||
<div class="controls">
|
||||
<input type="button" class="top" id="pauseBtn" value="pause" onclick="pause()" />
|
||||
<input type="button" class="top" id="showAllBtn" value="show all" onclick="showAll()" />
|
||||
<a id="download" class="top" onclick="downloadCanvasCommon()">Download</a> <br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="module" src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
176
dotLines/src/js/main.js
Normal file
@@ -0,0 +1,176 @@
|
||||
import {
|
||||
docReady, downloadCanvasWithoutButton, getMousePos, pointDistance, roundedRandom
|
||||
} from "canvas-common";
|
||||
|
||||
|
||||
|
||||
|
||||
var canvas;
|
||||
var ctx;
|
||||
var drawn = {};
|
||||
var mousePos = {};
|
||||
|
||||
var animationId;
|
||||
|
||||
var config = {
|
||||
size: {
|
||||
height: window.innerHeight,
|
||||
width: window.innerWidth
|
||||
},
|
||||
dotLines: {
|
||||
dotAmount: (window.innerHeight * window.innerWidth) / 4000,
|
||||
boxWidth: 50,
|
||||
boxHeight: 50,
|
||||
maxLinks: 10,
|
||||
mouseRange: 100,
|
||||
numberOfIncrements: 50,
|
||||
paused: false,
|
||||
showAll: false,
|
||||
minOpacity: 0.1,
|
||||
fps: 30,
|
||||
linkRange: 100
|
||||
}
|
||||
};
|
||||
|
||||
var currentNum = 0;
|
||||
|
||||
var dots = [];
|
||||
|
||||
|
||||
function createDots() {
|
||||
for (var i = 0; i < config.dotLines.dotAmount; i++) {
|
||||
var dot = {};
|
||||
dot.x = roundedRandom(config.size.width);
|
||||
dot.y = roundedRandom(config.size.height);
|
||||
dot.origin = {x: dot.x, y: dot.y};
|
||||
createTarget(dot);
|
||||
startDotMovement(dot);
|
||||
dot.num = currentNum++;
|
||||
dot.links = [];
|
||||
dots.push(dot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function createLines() {
|
||||
dots.forEach(function (linkingDot) {
|
||||
dots.forEach(function (linkedDot) {
|
||||
if (linkingDot.links.length >= config.dotLines.maxLinks || linkedDot.links.length >= config.dotLines.maxLinks) return;
|
||||
var dist = pointDistance(linkingDot, linkedDot);
|
||||
if (dist < config.dotLines.linkRange && linkedDot.links.indexOf(linkingDot) == -1) {
|
||||
linkingDot.links.push(linkedDot);
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function renderDot(dotToRender) {
|
||||
if (dotToRender.num in drawn) return;
|
||||
var mouseDistance = pointDistance(dotToRender, mousePos);
|
||||
if ((mouseDistance > config.dotLines.mouseRange || mouseDistance == undefined || isNaN(parseInt(mouseDistance))) && !config.dotLines.showAll) return;
|
||||
drawn[dotToRender.num] = 1;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(dotToRender.x, dotToRender.y);
|
||||
var alpha = Math.max(config.dotLines.minOpacity, 1 - (mouseDistance / config.dotLines.mouseRange));
|
||||
// in case we want to show everything with full opacity
|
||||
//var alpha = Math.max(!config.dotLines.showAll ? config.dotLines.minOpacity : 1, 1 - (mouseDistance / config.dotLines.mouseRange));
|
||||
ctx.fillStyle = 'rgba(255, 0, 0, ' + alpha + ')';
|
||||
ctx.arc(dotToRender.x, dotToRender.y, 3, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = 'rgba(255, 0, 0, ' + alpha + ')';
|
||||
dotToRender.links.forEach(function (tar) {
|
||||
ctx.moveTo(dotToRender.x, dotToRender.y);
|
||||
ctx.lineTo(tar.x, tar.y);
|
||||
});
|
||||
ctx.stroke();
|
||||
dotToRender.links.forEach(renderDot)
|
||||
}
|
||||
|
||||
function createTarget(dot) {
|
||||
dot.target = {
|
||||
x: dot.origin.x - config.dotLines.boxWidth / 2 + roundedRandom(config.dotLines.boxWidth),
|
||||
y: dot.origin.y - config.dotLines.boxHeight / 2 + roundedRandom(config.dotLines.boxHeight)
|
||||
};
|
||||
}
|
||||
function startDotMovement(dot) {
|
||||
dot.targetReached = false;
|
||||
createTarget(dot);
|
||||
var dist = pointDistance(dot, dot.target);
|
||||
var vect = {
|
||||
x: dot.target.x - dot.x,
|
||||
y: dot.target.y - dot.y
|
||||
};
|
||||
vect.x /= dist;
|
||||
vect.y /= dist;
|
||||
dot.distRemaining = dist;
|
||||
dot.vect = vect;
|
||||
}
|
||||
|
||||
function act(dot) {
|
||||
if (dot.targetReached) {
|
||||
startDotMovement(dot);
|
||||
dot.x += dot.vect.x * (dot.distRemaining / config.dotLines.numberOfIncrements);
|
||||
dot.y += dot.vect.y * (dot.distRemaining / config.dotLines.numberOfIncrements);
|
||||
} else {
|
||||
dot.x += dot.vect.x * (dot.distRemaining / config.dotLines.numberOfIncrements);
|
||||
dot.y += dot.vect.y * (dot.distRemaining / config.dotLines.numberOfIncrements);
|
||||
if (pointDistance(dot, dot.target) < 10) {
|
||||
dot.targetReached = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function renderDots() {
|
||||
drawn = {};
|
||||
ctx.clearRect(0, 0, config.size.width, config.size.height);
|
||||
dots.forEach(renderDot);
|
||||
dots.forEach(act);
|
||||
setTimeout(function () {
|
||||
if(!config.dotLines.paused) {
|
||||
animationId = requestAnimationFrame(renderDots);
|
||||
}
|
||||
}, 1000 / config.dotLines.fps)
|
||||
}
|
||||
|
||||
function setMousePos(e) {
|
||||
mousePos = getMousePos(canvas, e);
|
||||
}
|
||||
|
||||
|
||||
function pause() {
|
||||
config.dotLines.paused = !config.dotLines.paused;
|
||||
if (!config.dotLines.paused) {
|
||||
animationId = requestAnimationFrame(renderDots);
|
||||
} else {
|
||||
cancelAnimationFrame(animationId);
|
||||
}
|
||||
}
|
||||
|
||||
function showAll() {
|
||||
config.dotLines.showAll = !config.dotLines.showAll;
|
||||
}
|
||||
|
||||
|
||||
docReady(function () {
|
||||
canvas = document.getElementById('canvas');
|
||||
canvas.width = config.size.width;
|
||||
canvas.height = config.size.height;
|
||||
canvas.onmousemove = setMousePos;
|
||||
ctx = canvas.getContext("2d");
|
||||
|
||||
createDots();
|
||||
createLines();
|
||||
requestAnimationFrame(renderDots);
|
||||
});
|
||||
|
||||
|
||||
function downloadCanvasDotlines() {
|
||||
downloadCanvasWithoutButton('dotLines', canvas);
|
||||
}
|
||||
|
||||
|
||||
window.downloadCanvasCommon = downloadCanvasDotlines;
|
||||
window.pause = pause;
|
||||
window.showAll = showAll;
|
||||
24
dotLines/src/js/plugins.js
Normal file
@@ -0,0 +1,24 @@
|
||||
// Avoid `console` errors in browsers that lack a console.
|
||||
(function() {
|
||||
var method;
|
||||
var noop = function () {};
|
||||
var methods = [
|
||||
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
|
||||
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
|
||||
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
|
||||
'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn'
|
||||
];
|
||||
var length = methods.length;
|
||||
var console = (window.console = window.console || {});
|
||||
|
||||
while (length--) {
|
||||
method = methods[length];
|
||||
|
||||
// Only stub undefined methods.
|
||||
if (!console[method]) {
|
||||
console[method] = noop;
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
||||
// Place any jQuery/helper plugins in here.
|
||||
9
dotLines/vite.config.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
base: './',
|
||||
root: 'src',
|
||||
build: {
|
||||
outDir: '../../dist/dotLines'
|
||||
}
|
||||
})
|
||||
BIN
img/bubbles.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
img/circleBs.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
img/clusterFilter.png
Normal file
|
After Width: | Height: | Size: 123 KiB |
BIN
img/collatzConjecture.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
img/dotLines.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
img/survivors.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
@@ -13,5 +13,11 @@
|
||||
<a href="/recBubbles"><img src="img/recBubbles.png" alt="Recursive bubbles" class="preview" title="Recursive bubbles"></a> <br>
|
||||
<a href="/fireWorks"><img src="img/fireWorks.png" alt="Fireworks" class="preview" title="Fireworks"></a>
|
||||
<a href="/balls"><img src="img/balls.png" alt="Balls" class="preview" title="Balls"></a>
|
||||
<a href="/bubbles"><img src="img/bubbles.png" alt="Bubbles" class="preview" title="Bubbles"></a>
|
||||
<a href="/circleBs"><img src="img/circleBs.png" alt="circleBs" class="preview" title="circleBs"></a>
|
||||
<a href="/clusterFilter"><img src="img/clusterFilter.png" alt="clusterFilter" class="preview" title="clusterFilter"></a>
|
||||
<a href="/collatzConjecture"><img src="img/collatzConjecture.png" alt="collatzConjecture" class="preview" title="collatzConjecture"></a>
|
||||
<a href="/dotLines"><img src="img/dotLines.png" alt="dotLines" class="preview" title="dotLines"></a>
|
||||
<a href="/survivors"><img src="img/survivors.png" alt="survivors" class="preview" title="survivors"></a>
|
||||
</body>
|
||||
</html>
|
||||