Skip to content

Commit

Permalink
Merge pull request #186 from SimonStnn/dev
Browse files Browse the repository at this point in the history
1.9.0 update
  • Loading branch information
SimonStnn authored May 18, 2024
2 parents a864f60 + 9586c22 commit 6135a89
Show file tree
Hide file tree
Showing 30 changed files with 232 additions and 65 deletions.
26 changes: 6 additions & 20 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
- [build:firefox](#buildfirefox)
- [build:firefox:zip](#buildfirefoxzip)
- [Architecture](#architecture)
- [Secure spawn messages](#secure-spawn-messages)
- [Balloon spawn chances](#balloon-spawn-chances)
- [Balloons](#balloons)
- [Abstract balloon class](#abstract-balloon-class)
- [Default balloon](#default-balloon)
Expand Down Expand Up @@ -151,27 +151,13 @@ The zip file will be created in the `build/` directory.

## Architecture

### Secure spawn messages

To prevent spawning balloons from untrusted sources like devtools, the extension keeps secrets in the content script an background.
## Balloon spawn chances

```mermaid
sequenceDiagram
participant Content
participant Background
Content->>Background: Get secret
Background->>Content: Secret
Note over Background,Content: Secret is stored
loop Random interval
Background->>Content: Spawn balloon
alt Secret is correct
Note over Content: Balloon is spawned
Content->>Background: Get secret
Background->>Content: Secret
Note over Background,Content: Secret is stored
end
end
pie showdata
title Balloon spawn chances
"Default" : 0.90
"Confetti" : 0.10
```

## Balloons
Expand Down
Binary file added docs/images/Screenshot-1-1280x800.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/images/Screenshot-1.png
Binary file not shown.
Binary file added docs/images/Screenshot-2-1280x800.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/images/Screenshot-2-640x400.png
Binary file not shown.
Binary file removed docs/images/Screenshot-2.png
Binary file not shown.
Binary file added docs/images/Screenshot-3-1280x800.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/images/Screenshot-3-640x400.png
Binary file not shown.
Binary file removed docs/images/Screenshot-3.png
Binary file not shown.
Binary file removed docs/images/Screenshot-4-640x400.png
Binary file not shown.
Binary file removed docs/images/Screenshot-4.png
Binary file not shown.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pop-a-loon",
"version": "1.8.1",
"version": "1.9.0",
"description": "The new rising trend (literally) that changes the browser game completely.",
"private": true,
"scripts": {
Expand Down
17 changes: 17 additions & 0 deletions resources/balloons/confetti/confetti.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@keyframes bang {
from {
transform: translate3d(0, 0, 0);
opacity: 1;
}
}

i.particle {
animation: bang 750ms ease-out forwards;
position: absolute;
display: block;
left: 50%;
top: 0;
width: 3px;
height: 8px;
opacity: 0;
}
Binary file added resources/balloons/confetti/mask.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/balloons/default/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions resources/icons/balloon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/icons/icon-128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/icons/icon-16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/icons/icon-24.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/icons/icon-32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/icons/icon-48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/background/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import storage from '@/storage';
import remote from '@/remote';
import {
calculateBalloonSpawnDelay,
generateRandomNumber,
random,
getBrowser,
isRunningInBackground,
sendMessage,
Expand Down Expand Up @@ -102,7 +102,7 @@ const updateBadgeColors = () => {
// Get all active tabs
const tabs = await browser.tabs.query({ active: true });
// Select a random tab
const num = Math.round(generateRandomNumber(0, tabs.length - 1));
const num = Math.round(random(0, tabs.length - 1));
const tab = tabs[num];
if (!tab.id) return skipSpawnMessage('No tab id');

Expand Down
70 changes: 48 additions & 22 deletions src/balloon.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import browser from 'webextension-polyfill';
import storage from '@/storage';
import { generateRandomNumber, sendMessage } from '@utils';
import { random, sendMessage } from '@utils';

export const balloonContainer = document.createElement('div');
balloonContainer.id = 'balloon-container';

const resourceLocation = browser.runtime.getURL('resources/balloons/');
export const balloonResourceLocation = browser.runtime.getURL(
'resources/balloons/'
);
export const defaultBalloonFolderName = 'default';
export const defaultBalloonResourceLocation =
balloonResourceLocation + `${defaultBalloonFolderName}/`;

const buildBalloonElement = (
element: HTMLDivElement,
props: {
balloonImage: HTMLImageElement;
size: number;
positionX: number;
riseDuration: number;
Expand All @@ -19,9 +23,6 @@ const buildBalloonElement = (
) => {
element.classList.add('balloon');

// Add an image to the balloon
element.appendChild(props.balloonImage);

// Set the balloon's width and height
element.style.width = props.size + 'px';
element.style.height = element.style.width;
Expand All @@ -37,66 +38,91 @@ const buildBalloonElement = (

export default abstract class Balloon {
public abstract readonly name: string;
public abstract getRandomDuration(): number;

private readonly element: HTMLDivElement;
private readonly _popSound: HTMLAudioElement = new Audio();

protected readonly balloonImage: HTMLImageElement =
document.createElement('img');

public readonly element: HTMLDivElement;
public readonly riseDurationThreshold: [number, number] = [10000, 15000];

public get popSound(): HTMLAudioElement {
if (!this._popSound.src) this._popSound.src = this.popSoundUrl;
if (!this._popSound.src) {
this._popSound.src = this.popSoundUrl;
}
return this._popSound;
}

public get balloonImageUrl(): string {
return resourceLocation + this.name + '/icon.png';
return balloonResourceLocation + this.name + '/icon.png';
}

public get popSoundUrl(): string {
return resourceLocation + this.name + '/pop.mp3';
return balloonResourceLocation + this.name + '/pop.mp3';
}

constructor() {
// Create the balloon element
this.element = document.createElement('div');

// Add the balloon image to the balloon element
this.element.appendChild(this.balloonImage);

// Add an event listener to the balloon
this.element.addEventListener('click', this.pop.bind(this));
this.element.addEventListener('click', this._pop.bind(this));

this.balloonImage.addEventListener('error', (e) => {
this.balloonImage.src = defaultBalloonResourceLocation + 'icon.png';
});
}

public isRising() {
public isRising(): boolean {
return this.element.style.animationName === 'rise';
}

public rise() {
public getRandomDuration(
duration: [number, number] = this.riseDurationThreshold
): number {
return random(duration[0], duration[1]);
}

public rise(): void {
// Load the balloon image
this.balloonImage.src = this.balloonImageUrl;
// Build the balloon element
buildBalloonElement(this.element, {
size: generateRandomNumber(50, 75),
balloonImage: this.balloonImage,
positionX: generateRandomNumber(5, 95),
size: random(50, 75),
positionX: random(5, 95),
riseDuration: this.getRandomDuration(),
onAnimationend: this.remove.bind(this),
});
// Add the balloon to the container
balloonContainer.appendChild(this.element);
}

public remove() {
public remove(): void {
this.element.remove();
this.element.style.animationName = 'none';
}

public async pop() {
private async _pop(event: MouseEvent): Promise<void> {
// Remove the balloon
this.remove();

// Send message with the new count
sendMessage({ action: 'incrementCount' });

// Set volume
this.popSound.volume = (await storage.get('config')).popVolume / 100;
// Play the pop sound
this.popSound.play();
this.popSound.play().catch((e) => {
this.popSound.src = defaultBalloonResourceLocation + 'pop.mp3';
this.popSound.play();
});

// Send message with the new count
sendMessage({ action: 'incrementCount' });
this.pop(event);
}

public pop(event?: MouseEvent): void | Promise<void> {}
}
83 changes: 83 additions & 0 deletions src/balloons/confetti.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import Balloon, { balloonResourceLocation } from '@/balloon';
import { random } from '@/utils';
import '@/../resources/balloons/confetti/confetti.css';

export default class Confetti extends Balloon {
public readonly name = 'confetti';
public static readonly spawn_chance = 0.1;

private readonly mask = document.createElement('img');

constructor() {
super();

this.element.appendChild(this.mask);
this.mask.src = balloonResourceLocation + this.name + '/mask.png';
this.mask.style.position = 'absolute';
this.mask.style.top = '-10px';
this.mask.style.left = '0';
// Give it a random rotation
this.mask.style.transform = `rotate(${Math.random() * 360}deg)`;
}

public pop(event?: MouseEvent) {
// Get the click position
const x = event?.clientX || window.innerWidth / 2;
const y = event?.clientY || window.innerHeight / 2;
// Add an element to that position
const confetti = document.createElement('div');
confetti.style.position = 'absolute';
confetti.style.top = `${y}px`;
confetti.style.left = `${x}px`;
confetti.style.zIndex = '1000';
confetti.style.pointerEvents = 'none';
document.body.appendChild(confetti);
// Throw confetti
throwConfetti(confetti, 100);
// Remove the confetti after 2 seconds
setTimeout(() => {
confetti.remove();
}, 2000);
}
}

function throwConfetti(element: HTMLElement, amount: number = 100) {
const df = document.createDocumentFragment();
const offset = 10;
const particles: HTMLElement[] = [];
for (let i = 0; i < amount; i++) {
const c = document.createElement('i');
c.className = 'particle';
const angle = random(360);
const radius = random(250);
let x = radius * Math.cos(angle);
let y = radius * Math.sin(angle);
c.style.cssText = `
transform: translate3d(${x}px, ${y}px, 0)
rotate(${angle}deg);
background: hsla(${random(360)},100%,50%,1);
`;
df.appendChild(c);
particles.push(c);
}
element.appendChild(df);

function checkBounds() {
particles.forEach((particle, index) => {
const rect = particle.getBoundingClientRect();
if (
rect.bottom < +offset ||
rect.top > window.innerHeight - offset ||
rect.left > window.innerWidth - offset ||
rect.right < +offset
) {
particle.remove();
particles.splice(index, 1);
}
});
if (particles.length > 0) {
requestAnimationFrame(checkBounds);
}
}
requestAnimationFrame(checkBounds);
}
11 changes: 3 additions & 8 deletions src/balloons/default.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import Balloon from '@/balloon';
import { generateRandomNumber } from '@/utils';
import Balloon, { defaultBalloonFolderName } from '@/balloon';

export default class Default extends Balloon {
public readonly name = 'default';
public static readonly spawn_chance = 0.95;

getRandomDuration() {
return generateRandomNumber(10000, 15000);
}
public readonly name = defaultBalloonFolderName;
public static readonly spawn_chance = 0.9;
}
1 change: 1 addition & 0 deletions src/balloons/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default as Default } from './default';
export { default as Confetti } from './confetti';
Loading

0 comments on commit 6135a89

Please sign in to comment.