Created
December 30, 2024 16:37
-
-
Save abradley2/e7d889533bbff3461ca4bc6094490fb0 to your computer and use it in GitHub Desktop.
AsepriteLoader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { TaskEither } from "fp-ts/lib/TaskEither" | |
import { Assets, Spritesheet, SpritesheetData, SpritesheetFrameData } from "pixi.js" | |
import * as io from "io-ts" | |
import { HandledError } from "./errors" | |
import * as taskEither from "fp-ts/lib/TaskEither" | |
import { pipe } from "fp-ts/lib/function" | |
import * as errors from "./errors" | |
const frameDecoder = io.type({ | |
filename: io.string, | |
frame: io.type({ | |
x: io.number, | |
y: io.number, | |
w: io.number, | |
h: io.number, | |
}), | |
sourceSize: io.type({ | |
w: io.number, | |
h: io.number, | |
}), | |
duration: io.number, | |
}) | |
export type Frame = io.TypeOf<typeof frameDecoder> | |
const frameTagDecoder = io.type({ | |
name: io.string, | |
from: io.number, | |
to: io.number, | |
}) | |
export type FrameTag = io.TypeOf<typeof frameTagDecoder> | |
const metaDecoder = io.type({ | |
image: io.string, | |
size: io.type({ | |
w: io.number, | |
h: io.number, | |
}), | |
frameTags: io.array(frameTagDecoder), | |
}) | |
const asepriteDecoder = io.type({ | |
frames: io.array(frameDecoder), | |
meta: metaDecoder, | |
}) | |
export type Aseprite = io.TypeOf<typeof asepriteDecoder> | |
const cache : Record<string, Spritesheet> = {} | |
const requestCache : Record<string, Promise<unknown> | undefined> = {} | |
export function loadSprite (spriteJsonFilePath: string): TaskEither<HandledError, Spritesheet> { | |
if (cache[spriteJsonFilePath]) { | |
return taskEither.right(cache[spriteJsonFilePath]) | |
} | |
const siblingDir = spriteJsonFilePath. | |
split("/"). | |
slice(0, -1). | |
join("/") | |
return pipe( | |
taskEither.Do, | |
taskEither.bind("json", () => { | |
return taskEither.tryCatch( | |
() => { | |
if (requestCache[spriteJsonFilePath]) { | |
return requestCache[spriteJsonFilePath] | |
} | |
const response = fetch(spriteJsonFilePath, { cache: "no-store" }).then((res) => res.json()) | |
requestCache[spriteJsonFilePath] = response | |
return response | |
}, | |
errors.handleError(new Error(`Failed to fetch sprite file for ${spriteJsonFilePath}`)), | |
) | |
}), | |
taskEither.bind("parsedJson", ({ json }) => { | |
const result = asepriteDecoder.decode(json) | |
return pipe( | |
result, | |
taskEither.fromEither, | |
taskEither.mapLeft(errors.handleError(new Error(`Failed to parse sprite file for ${spriteJsonFilePath}`))), | |
) | |
}), | |
taskEither.bind("texture", ({ parsedJson }) => { | |
return taskEither.tryCatch( | |
() => Assets.load(`${siblingDir}/${parsedJson.meta.image}`), | |
errors.handleError(new Error(`Failed to load texture for sprite file ${spriteJsonFilePath}`)), | |
) | |
}), | |
taskEither.bind("spriteSheet", ({ texture, parsedJson }) => { | |
const atlasData: SpritesheetData = { | |
frames: parsedJson.frames.reduce((acc: Record<string, SpritesheetFrameData>, frame, idx) => { | |
acc[`${idx}`] = frame | |
return acc | |
}, {}), | |
meta: { | |
size: parsedJson.meta.size, | |
scale: 1, | |
}, | |
} | |
parsedJson.meta.frameTags.forEach((frameTag) => { | |
const frames = [] | |
for (let i = frameTag.from; i <= frameTag.to; i++) { | |
frames.push(`${i}`) | |
} | |
if (typeof atlasData.animations === "undefined") { | |
atlasData.animations = {} | |
} | |
atlasData.animations[frameTag.name] = frames | |
}) | |
return taskEither.right(new Spritesheet(texture, atlasData)) | |
}), | |
taskEither.bind("parsedSpriteSheet", ({ spriteSheet }) => { | |
return taskEither.tryCatch( | |
() => spriteSheet.parse(), | |
errors.handleError(new Error(`Failed to parse sprite sheet for sprite file ${spriteJsonFilePath}`)), | |
) | |
}), | |
taskEither.map(({ spriteSheet }) => { | |
cache[spriteJsonFilePath] = spriteSheet | |
return spriteSheet | |
}), | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment