Move anim class and stylesheet

This commit is contained in:
Idrees Hassan
2025-10-26 13:56:14 -04:00
parent a9f386b6bd
commit 45ed91a531
7 changed files with 147 additions and 139 deletions

48
src/anim.js Normal file
View File

@@ -0,0 +1,48 @@
import Frame from "./frame.js";
import { BirdType } from "./sprites";
class Anim {
/**
* @param {Frame[]} frames
* @param {number[]} durations
* @param {boolean} loop
*/
constructor(frames, durations, loop = true) {
this.frames = frames;
this.durations = durations;
this.loop = loop;
}
getAnimationDuration() {
return this.durations.reduce((a, b) => a + b, 0);
}
/**
* @param {CanvasRenderingContext2D} ctx
* @param {number} direction
* @param {number} timeStart The start time of the animation in milliseconds
* @param {number} canvasPixelSize The size of a canvas pixel in pixels
* @param {BirdType} [species] The species to use for the animation
* @returns {boolean} Whether the animation is complete
*/
draw(ctx, direction, timeStart, canvasPixelSize, species) {
let time = Date.now() - timeStart;
const duration = this.getAnimationDuration();
if (this.loop) {
time %= duration;
}
let totalDuration = 0;
for (let i = 0; i < this.durations.length; i++) {
totalDuration += this.durations[i];
if (time < totalDuration) {
this.frames[i].draw(ctx, direction, canvasPixelSize, species);
return false;
}
}
// Draw the last frame if the animation is complete
this.frames[this.frames.length - 1].draw(ctx, direction, canvasPixelSize, species);
return true;
}
}
export default Anim;

View File

@@ -11,6 +11,7 @@ import {
import Frame from './frame.js';
import Layer from './layer.js';
import Anim from './anim.js';
// @ts-ignore
const SHARED_CONFIG = {
@@ -70,49 +71,6 @@ let userSettings = {};
const STYLESHEET = `___STYLESHEET___`;
class Anim {
/**
* @param {Frame[]} frames
* @param {number[]} durations
* @param {boolean} loop
*/
constructor(frames, durations, loop = true) {
this.frames = frames;
this.durations = durations;
this.loop = loop;
}
getAnimationDuration() {
return this.durations.reduce((a, b) => a + b, 0);
}
/**
* @param {CanvasRenderingContext2D} ctx
* @param {number} direction
* @param {number} timeStart The start time of the animation in milliseconds
* @param {BirdType} [species] The species to use for the animation
* @returns {boolean} Whether the animation is complete
*/
draw(ctx, direction, timeStart, species) {
let time = Date.now() - timeStart;
const duration = this.getAnimationDuration();
if (this.loop) {
time %= duration;
}
let totalDuration = 0;
for (let i = 0; i < this.durations.length; i++) {
totalDuration += this.durations[i];
if (time < totalDuration) {
this.frames[i].draw(ctx, direction, CANVAS_PIXEL_SIZE, species);
return false;
}
}
// Draw the last frame if the animation is complete
this.frames[this.frames.length - 1].draw(ctx, direction, CANVAS_PIXEL_SIZE, species);
return true;
}
}
const DEFAULT_BIRD = "bluebird";
const SPRITE_WIDTH = 32;
@@ -710,7 +668,7 @@ Promise.all([
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (currentAnimation.draw(ctx, direction, animStart, SPECIES[currentSpecies])) {
if (currentAnimation.draw(ctx, direction, animStart, CANVAS_PIXEL_SIZE, SPECIES[currentSpecies])) {
setAnimation(Animations.STILL);
}
@@ -909,7 +867,7 @@ Promise.all([
return;
}
// Draw the decoration
DECORATION_ANIMATIONS.mac.draw(decorationCtx, Directions.LEFT, Date.now());
DECORATION_ANIMATIONS.mac.draw(decorationCtx, Directions.LEFT, CANVAS_PIXEL_SIZE, Date.now());
// Add the decoration to the page
document.body.appendChild(decorationCanvas);
makeDraggable(decorationCanvas, false);
@@ -945,7 +903,7 @@ Promise.all([
if (!featherCtx) {
return;
}
FEATHER_ANIMATIONS.feather.draw(featherCtx, Directions.LEFT, Date.now(), type);
FEATHER_ANIMATIONS.feather.draw(featherCtx, Directions.LEFT, Date.now(), CANVAS_PIXEL_SIZE, type);
document.body.appendChild(featherCanvas);
onClick(featherCanvas, () => {
unlockBird(birdType);

344
src/stylesheet.css Normal file
View File

@@ -0,0 +1,344 @@
:root {
--birb-border-size: 2px;
--birb-neg-border-size: calc(var(--birb-border-size) * -1);
--birb-double-border-size: calc(var(--birb-border-size) * 2);
--birb-neg-double-border-size: calc(var(--birb-neg-border-size) * 2);
--birb-highlight: #ffa3cb;
--birb-border-color: var(--birb-highlight);
--birb-background-color: #ffecda;
--birb-mix-color: color-mix(in srgb, var(--birb-highlight) 50%, var(--birb-background-color));
--birb-scale: ${BIRB_CSS_SCALE};
--birb-ui-scale: ${UI_CSS_SCALE};
}
#birb {
image-rendering: pixelated;
position: fixed;
bottom: 0;
transform: scale(var(--birb-scale)) !important;
transform-origin: bottom;
z-index: 2147483638 !important;
cursor: pointer;
}
.birb-absolute {
position: absolute !important;
}
.birb-decoration {
image-rendering: pixelated;
position: fixed;
bottom: 0;
transform: scale(var(--birb-scale)) !important;
transform-origin: bottom;
z-index: 2147483630 !important;
}
.birb-window {
font-family: "Monocraft", monospace !important;
line-height: initial !important;
color: #000000 !important;
z-index: 2147483639 !important;
position: fixed;
background-color: var(--birb-background-color);
box-shadow:
var(--birb-border-size) 0 var(--birb-border-color),
var(--birb-neg-border-size) 0 var(--birb-border-color),
0 var(--birb-neg-border-size) var(--birb-border-color),
0 var(--birb-border-size) var(--birb-border-color),
var(--birb-double-border-size) 0 var(--birb-border-color),
var(--birb-neg-double-border-size) 0 var(--birb-border-color),
0 var(--birb-neg-double-border-size) var(--birb-border-color),
0 var(--birb-double-border-size) var(--birb-border-color),
0 0 0 var(--birb-border-size) var(--birb-border-color),
0 0 0 var(--birb-double-border-size) white,
var(--birb-double-border-size) 0 0 var(--birb-border-size) white,
var(--birb-neg-double-border-size) 0 0 var(--birb-border-size) white,
0 var(--birb-neg-double-border-size) 0 var(--birb-border-size) white,
0 var(--birb-double-border-size) 0 var(--birb-border-size) white;
box-sizing: border-box;
display: flex;
flex-direction: column;
transform: scale(var(--birb-ui-scale)) !important;
animation: pop-in 0.08s;
transition-timing-function: ease-in;
}
#birb-menu {
transition-duration: 0.2s;
transition-timing-function: ease-out;
min-width: 140px;
z-index: 2147483639 !important;
}
#birb-menu-exit {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 2147483637 !important;
}
@keyframes pop-in {
0% {
opacity: 1;
transform: scale(0.1);
}
100% {
opacity: 1;
transform: scale(var(--birb-ui-scale));
}
}
.birb-window-header {
box-sizing: border-box;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 7px;
padding-top: 3px;
padding-bottom: 3px;
padding-left: 30px;
padding-right: 30px;
background-color: var(--birb-highlight);
box-shadow:
var(--birb-border-size) 0 var(--birb-highlight),
var(--birb-neg-border-size) 0 var(--birb-highlight),
0 var(--birb-neg-border-size) var(--birb-highlight),
var(--birb-neg-border-size) var(--birb-border-size) var(--birb-border-color),
var(--birb-border-size) var(--birb-border-size) var(--birb-border-color);
color: var(--birb-border-color) !important;
font-size: 16px;
}
.birb-window-title {
text-align: center;
flex-grow: 1;
user-select: none;
color: var(--birb-background-color);
}
.birb-window-close {
position: absolute;
top: 1px;
right: 0;
color: var(--birb-background-color);
user-select: none;
cursor: pointer;
padding-left: 5px;
padding-right: 5px;
}
.birb-window-close:hover {
transform: scale(1.1);
}
.birb-window-content {
box-sizing: border-box;
background-color: var(--birb-background-color);
margin-top: var(--birb-border-size);
flex-grow: 1;
box-shadow:
var(--birb-border-size) 0 var(--birb-background-color),
var(--birb-neg-border-size) 0 var(--birb-background-color),
0 var(--birb-border-size) var(--birb-background-color),
0 var(--birb-neg-border-size) var(--birb-border-color),
0 var(--birb-border-size) var(--birb-border-color);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding-top: calc(var(--birb-double-border-size));
padding-bottom: var(--birb-border-size);
}
.birb-pico-8-content {
background: #111111;
box-shadow: none;
display: flex;
justify-content: center;
overflow: hidden;
border: none;
}
.birb-pico-8-content iframe {
width: 300px;
margin-left: -15px;
margin-right: -30px;
margin-top: -10px;
margin-bottom: -23px;
border: none;
aspect-ratio: 1;
}
.birb-music-player-content {
background: var(--birb-background-color);
box-shadow:
var(--birb-border-size) 0 var(--birb-background-color),
var(--birb-neg-border-size) 0 var(--birb-background-color),
0 var(--birb-border-size) var(--birb-background-color),
0 var(--birb-neg-border-size) var(--birb-border-color),
0 var(--birb-border-size) var(--birb-border-color);
display: flex;
justify-content: center;
overflow: hidden;
padding: 10px;
}
.birb-menu-item {
width: calc(100% - var(--birb-double-border-size));
font-size: 14px;
padding-top: 4px;
padding-bottom: 4px;
padding-left: 10px;
padding-right: 10px;
box-sizing: border-box;
opacity: 0.7 !important;
user-select: none;
display: flex;
justify-content: space-between;
cursor: pointer;
color: black !important;
}
.birb-menu-item:hover {
opacity: 1 !important;
background: var(--birb-highlight) !important;
color: white !important;
box-shadow:
var(--birb-border-size) 0 var(--birb-highlight),
var(--birb-neg-border-size) 0 var(--birb-highlight),
0 var(--birb-neg-border-size) var(--birb-highlight),
0 var(--birb-border-size) var(--birb-highlight);
}
.birb-menu-item-arrow {
display: inline-block;
}
.birb-window-separator {
width: 100%;
height: var(--birb-border-size);
background-color: var(--birb-border-color);
box-sizing: border-box;
margin-top: var(--birb-double-border-size);
margin-bottom: var(--birb-double-border-size);
opacity: 0.4;
}
#birb-field-guide {
width: 340px;
}
.birb-grid-content {
width: 100%;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
flex-direction: row;
padding-top: 4px;
padding-bottom: 4px;
padding-left: 10px;
padding-right: 10px;
box-sizing: border-box;
}
.birb-grid-item {
width: 64px;
height: 64px;
overflow: hidden;
margin-top: 6px;
margin-bottom: 6px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.birb-grid-item:hover {
border-color: var(--birb-highlight);
}
.birb-grid-item canvas {
image-rendering: pixelated;
transform: scale(2);
padding-bottom: var(--birb-border-size);
}
.birb-grid-item, .birb-field-guide-description, .birb-message-content {
border: var(--birb-border-size) solid rgb(255, 207, 144);
box-shadow: 0 0 0 var(--birb-border-size) white;
background: rgba(255, 221, 177, 0.5);
}
.birb-grid-item-locked {
cursor: auto;
filter: grayscale(100%) sepia(30%);
}
.birb-grid-item-locked canvas {
filter: contrast(90%);
}
.birb-grid-item-selected {
border: var(--birb-border-size) solid var(--birb-highlight);
background: var(--birb-mix-color);
}
.birb-field-guide-description {
width: calc(100% - 20px);
margin-top: 5px;
padding: 8px;
padding-top: 4px;
padding-bottom: 4px;
margin-bottom: 10px;
font-size: 14px;
box-sizing: border-box;
color: rgb(124, 108, 75);
}
#birb-feather {
cursor: pointer;
}
.birb-message-content {
box-sizing: border-box;
width: 100%;
margin-top: 10px;
padding: 8px;
padding-top: 4px;
padding-bottom: 4px;
font-size: 14px;
color: rgb(124, 108, 75);
}
.birb-sticky-note {
position: absolute;
box-sizing: border-box;
}
.birb-sticky-note > .birb-window-content {
padding: 0;
}
.birb-sticky-note-input {
width: 100%;
height: 100%;
padding: 10px !important;
resize: both !important;
min-width: 175px !important;
min-height: 135px !important;
box-sizing: border-box !important;
font-family: "Monocraft", monospace !important;
font-size: 14px !important;
color: black !important;
background-color: transparent !important;
border: none !important;
}
.birb-sticky-note-input:focus {
outline: none;
}