alchemy-engine v0.1.7
:alembic: alchemy engine
👾 Easily make 2D browser games with pixi.js
:sparkles: Features
- 100% Type-Safe
- Batteries included (get started using one CLI command)
- Reactive - Re-render view when state changes
- Object pooling
- Timer - Run logic every X ticks
- Animations
- Debug overlay
- Keyboard input
- Sounds
- Sprite sheet generation
- Scenes
- CLI - Create project and components
- CI - Workflows to build, test and deploy to
itch.io
- Screen shake
- Uses
vite
for a super fast and modern dev server
Getting started
npx alchemy-create@latest create <game-name>
Module API
These are imported directly from alchemy-engine
create
Convenience functions to create Pixi objects
sprite
import { sprite } from "alchemy-engine";
sprite(container, textures["./square-1"]);
animatedSprite
import { animatedSprite } from "alchemy-engine";
animatedSprite(container, [textures["./square-1"]]);
text
import { text } from "alchemy-engine";
text(container, textStyle, "Hello world");
htmlText
import { htmlText } from "alchemy-engine";
htmlText(container, textStyle, "Hello world");
bitmapText
import { bitmapText } from "alchemy-engine";
bitmapText(container, textStyle, "Hello world");
container
import { container } from "alchemy-engine";
container(_container);
graphics
import { graphics } from "alchemy-engine";
graphics(container);
rectangle
import { rectangle } from "alchemy-engine";
rectangle(container, { x: 0, y: 0, width: 10, height: 10 });
event
onClick
Convenience functions for mouse input
import { onClick } from "alchemy-engine";
onClick(container, () => {
console.log("Clicked!");
});
onHover
import { onHover } from "alchemy-engine";
onHover(container, {
onOver() {
console.log("Hovered!");
},
onOut() {
console.log("Not hovered!");
},
});
sync
sync
syncPosition
keys
arrowKeys
Constants for all arrow keys
import { arrowKeys } from "alchemy-engine";
export const keys = ["a", "w", "s", "d", ...arrowKeys] as const;
position
TODO
getAllChildren
TODO
getAllLeafChildren
TODO
debug
logObject
Nicely log a Pixi object. Set label
property for best result.
import { logObject } from "alchemy-engine";
const sprite = new Sprite();
sprite.label = "sprite";
logObject(sprite);
boundsToString
Enables easier logging of sprite bounds
import { boundsToString } from "alchemy-engine";
console.log(boundsToString(sprite));
contains
Check if a point is within the bounds of an object
import { contains } from "alchemy-engine";
if (contains(sprite, { x: 1, y: 1 })) {
// point is within bounds of sprite
}
intersects
Check if the bounds of two objects are intersecting
import { intersects } from "alchemy-engine";
if (intersects(sprite1, sprite2)) {
// sprites are intersecting
}
type guards
isAnimatedSprite
import { isAnimatedSprite } from "alchemy-engine";
if (isAnimatedSprite(sprite)) {
// sprite is of type AnimatedSprite
}
loadDataFromImage
This function can be used to for example load a level from image data
import { loadDataFromImage } from "alchemy-engine";
import map from "~/public/asset/map.png?url";
const { pixels, width, height } = await loadDataFromImage(map);
console.log(pixels);
// ['255-255-255', '0-0-0']
pool
Scene API
The arguments passed to a scene
{
textures,
container,
input,
state,
timer,
sound,
app,
timer,
useScreenShake,
}: Scene
textures
An object containing all textures by name
Record<TextureName, Texture>;
function myScene({ textures, container }: Scene) {
sprite(container, textures["./square1"]);
}
getTextures
Get multiple textures
function myScene({ getTextures, container }: Scene) {
const textures = getTextures(["./texture-1", "./texture-2"]);
animatedSprite(container, textures);
}
useScreenShake
Enable the use of screen shake
const screenShake = useScreenShake(container);
screenShake.add(0.5);
animate
- sine
- easeOut
- easeIn
These functions all require an onUpdate
and duration
argument
Optionally you can pass a startValue
(default: 0) and endValue
(default: 1)
util
- center
app
The Pixi Application
instance
music
Record<MusicName, Howl>;
sound
Record<SoundName, Howl>;
setScene
setScene("mainMenu");
global
timer
A timer that doesn't get cancelled when changing scenes
container
A scene specific Pixi container. Will be destroyed when scene is changed.
state
Set state to trigger sync
and subscribe
functions
subscribe, subscribeKey, proxy
Re-exported from valtio
timer
delay
// Wait 100 updates
await delay(100);
repeatUntil
Execute a callback every update until duration
is reached
await repeatUntil(3, (time, deltaTime) => {});
repeatEvery
Execute a callback forever every interval
updates
Returns a cancel
function
const cancel = repeatEvery(3, (time, deltaTime) => {});
input
debouncedKey
debouncedKey(
// Key id
"d",
// Callback
() => {
s.position.x += 1;
},
// Delay between key presses
10
);
isKeyDown
Check if a key is currently being pressed
repeatEvery(1, () => {
if (isKeyDown(["a", "ArrowLeft"])) {
s.position.x -= 1;
}
if (isKeyDown(["d", "ArrowRight"])) {
s.position.x += 1;
}
});
random
There is a built-in seedable random module.
To set the seed, pass it in to createGame
The module uses the same API as park-miller, with some additions:
chance(percentage) => boolean
CLI
dev
Start the dev server. Listens to changes to source code, sprite
, src/public/asset/sound
and src/public/asset/music
folders.
npx alchemy-cli dev
sprite
Generate sprite sheet
npx alchemy-cli sprite
sound
Load sounds
npx alchemy-cli sound
Dev
Run ./go.sh
to test that things work
See also
- State machine: xstate
- Noise simplex-noise
16 days ago
26 days ago
25 days ago
26 days ago
10 months ago
10 months ago
10 months ago
11 months ago
11 months ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago