canvaskit-wasm for Edge Scripting for bunny.net 🐰

NPM Version

Skia

Skia is a complete 2D graphic library for drawing text, geometries, and images.

Quickstart

Installation

mkdir skia-examplecd skia-examplenpm init -ynpm install @bunny.net/edgescript-sdk bunny-skianpm install --save-dev esbuild esbuild-plugin-node-protocol-imports tsx @tsconfig/node20

Add a build script to your package.json file:

{  "scripts": {    "build": "npx tsx src/esbuild"  }}

Example

Add TypeScript support:

tsconfig.json

{  "extends": "@tsconfig/node20/tsconfig.json",  "include": ["src"],  "compilerOptions": {    "noEmit": true,    "resolvePackageJsonExports": true  }}

Write the edge script:

src/index.ts

import CanvasKitInit, { locateFullCompressedFile } from 'bunny-skia'import type { CanvasKit as ICanvasKit } from 'bunny-skia'import * as BunnySDK from '@bunny.net/edgescript-sdk'let CanvasKit: ICanvasKitBunnySDK.net.http.serve(async (request: Request): Promise<Response> => {  // keep script startup time under 500ms  if (!CanvasKit) {    const file = await locateFullCompressedFile()    CanvasKit = await CanvasKitInit({      locateFile() {        return file      },    })  }  // generate image  let surface = CanvasKit.MakeSurface(300, 300)!  const canvas = surface.getCanvas()  const paint = new CanvasKit.Paint()  let robotoData = await getTestAsset('Roboto-Regular.woff')  const roboto = CanvasKit.Typeface.MakeFreeTypeFaceFromData(robotoData)!  const textPaint = new CanvasKit.Paint()  textPaint.setColor(CanvasKit.Color(40, 0, 0))  textPaint.setAntiAlias(true)  const textFont = new CanvasKit.Font(roboto, 30)  const skpath = starPath(CanvasKit)  const dpe = CanvasKit.PathEffect.MakeDash([15, 5, 5, 10], 1)  paint.setPathEffect(dpe)  paint.setStyle(CanvasKit.PaintStyle.Stroke)  paint.setStrokeWidth(5.0)  paint.setAntiAlias(true)  paint.setColor(CanvasKit.Color(66, 129, 164, 1.0))  canvas.clear(CanvasKit.Color(255, 255, 255, 1.0))  canvas.drawPath(skpath, paint)  canvas.drawText('Try Clicking!', 10, 280, textPaint, textFont)  surface.flush()  const img = surface.makeImageSnapshot()  const bytes = img.encodeToBytes(CanvasKit.ImageFormat.WEBP)!  // free wasm memory  img.delete()  dpe.delete()  skpath.delete()  textFont.delete()  textPaint.delete()  roboto.delete()  paint.delete()  surface.dispose()  // return image response  return new Response(bytes, {    headers: {      'Content-Type': 'image/webp',    },  })})function starPath(CanvasKit: ICanvasKit, X = 128, Y = 128, R = 116) {  let p = new CanvasKit.Path()  p.moveTo(X + R, Y)  for (let i = 1; i < 8; i++) {    let a = 2.6927937 * i    p.lineTo(X + R * Math.cos(a), Y + R * Math.sin(a))  }  return p}async function getTestAsset(name: string): Promise<Uint8Array> {  const response = await fetch(    `https://raw.githubusercontent.com/google/skia/main/modules/canvaskit/tests/assets/${name}`,  )  return await response.bytes()}

Create a build script:

src/esbuild.ts

import fs from 'node:fs/promises'import { builtinModules } from 'node:module'import { build } from 'esbuild'import esbuildPluginNodeProtocolImports from 'esbuild-plugin-node-protocol-imports'const MINIFY = process.env.MINIFY === 'false' ? false : trueconst allBuiltinModules = [  ...builtinModules,  ...builtinModules.map((builtinModule) => `node:${builtinModule}`),]await fs.rm('dist', {  recursive: true,  force: true,})await build({  alias: {    '@bunny.net/edgescript-sdk':      './node_modules/@bunny.net/edgescript-sdk/esm-bunny/lib.mjs',  },  banner: {    js: `import * as process from "node:process";import { Buffer } from "node:buffer";globalThis.process ??= process;globalThis.Buffer ??= Buffer;globalThis.global ??= globalThis;`,  },  bundle: true,  define: { 'process.env.NODE_ENV': '"production"' },  entryPoints: ['src/index.ts'],  external: allBuiltinModules,  format: 'esm',  keepNames: !MINIFY,  minify: MINIFY,  outdir: 'dist',  packages: 'bundle',  platform: 'node',  sourcemap: !MINIFY,  target: 'node20.17.0',  plugins: [esbuildPluginNodeProtocolImports],})

For more information on bundling for edge scripts, please read the guide.

Deployment

Build

npm run build

Deploy

npx --yes bunny-launcher@latest --interactive