alchemy-engine v0.1.4
:alembic: alchemy engine
👾 Easily make 2D browser games with pixi.js
:sparkles: Features
- Reactive - Re-render view when state changes
- Pooling - Create all game object up front - in render never add or remove game objects
- 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
- 100% Type-Safe
- Batteries included (get started using one CLI command)
- Uses
vite
for a super fast and modern dev server
:no_good: Out of scope
- State machine (Recommendation: xstate)
- Noise (Recommendation: simplex-noise)
- Physics
- Network
Getting started
npx alchemy-engine@latest create <game-name>
Module API
create
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
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
create
npx alchemy-engine@latest create <game-name>
dev
Start the dev server. Listens to changes to source code, sprite
, src/public/asset/sound
and src/public/asset/music
folders.
npx alchemy-engine@latest dev
sprite
Generate sprite sheet
npx alchemy-engine@latest sprite
sound
Load sounds
npx alchemy-engine@latest sound
8 months ago
8 months ago
8 months ago
9 months ago
9 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years 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