canvas-emulator 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitignore +233 -0
- package/CLAUDE.md +61 -0
- package/README.md +128 -0
- package/dist/cjs/playground.d.ts +2 -0
- package/dist/cjs/playground.d.ts.map +1 -0
- package/dist/cjs/playground.js +37 -0
- package/dist/cjs/playground.js.map +1 -0
- package/dist/cjs/src/canvas/canvas.d.ts +41 -0
- package/dist/cjs/src/canvas/canvas.d.ts.map +1 -0
- package/dist/cjs/src/canvas/canvas.js +83 -0
- package/dist/cjs/src/canvas/canvas.js.map +1 -0
- package/dist/cjs/src/canvas/context-2d.d.ts +37 -0
- package/dist/cjs/src/canvas/context-2d.d.ts.map +1 -0
- package/dist/cjs/src/canvas/context-2d.js +245 -0
- package/dist/cjs/src/canvas/context-2d.js.map +1 -0
- package/dist/cjs/src/canvas/index.d.ts +2 -0
- package/dist/cjs/src/canvas/index.d.ts.map +1 -0
- package/dist/cjs/src/canvas/index.js +18 -0
- package/dist/cjs/src/canvas/index.js.map +1 -0
- package/dist/cjs/src/common/array.d.ts +40 -0
- package/dist/cjs/src/common/array.d.ts.map +1 -0
- package/dist/cjs/src/common/array.js +99 -0
- package/dist/cjs/src/common/array.js.map +1 -0
- package/dist/cjs/src/common/colors.d.ts +62 -0
- package/dist/cjs/src/common/colors.d.ts.map +1 -0
- package/dist/cjs/src/common/colors.js +93 -0
- package/dist/cjs/src/common/colors.js.map +1 -0
- package/dist/cjs/src/common/hash.d.ts +3 -0
- package/dist/cjs/src/common/hash.d.ts.map +1 -0
- package/dist/cjs/src/common/hash.js +44 -0
- package/dist/cjs/src/common/hash.js.map +1 -0
- package/dist/cjs/src/common/index.d.ts +7 -0
- package/dist/cjs/src/common/index.d.ts.map +1 -0
- package/dist/cjs/src/common/index.js +23 -0
- package/dist/cjs/src/common/index.js.map +1 -0
- package/dist/cjs/src/common/ppm.d.ts +2 -0
- package/dist/cjs/src/common/ppm.d.ts.map +1 -0
- package/dist/cjs/src/common/ppm.js +21 -0
- package/dist/cjs/src/common/ppm.js.map +1 -0
- package/dist/cjs/src/common/scalar.d.ts +27 -0
- package/dist/cjs/src/common/scalar.d.ts.map +1 -0
- package/dist/cjs/src/common/scalar.js +65 -0
- package/dist/cjs/src/common/scalar.js.map +1 -0
- package/dist/cjs/src/common/types.d.ts +9 -0
- package/dist/cjs/src/common/types.d.ts.map +1 -0
- package/dist/cjs/src/common/types.js +3 -0
- package/dist/cjs/src/common/types.js.map +1 -0
- package/dist/cjs/src/data/font/index.d.ts +2 -0
- package/dist/cjs/src/data/font/index.d.ts.map +1 -0
- package/dist/cjs/src/data/font/index.js +18 -0
- package/dist/cjs/src/data/font/index.js.map +1 -0
- package/dist/cjs/src/data/font/noto-mono-regular-48.d.ts +747 -0
- package/dist/cjs/src/data/font/noto-mono-regular-48.d.ts.map +1 -0
- package/dist/cjs/src/data/font/noto-mono-regular-48.js +15544 -0
- package/dist/cjs/src/data/font/noto-mono-regular-48.js.map +1 -0
- package/dist/cjs/src/data/font/noto-mono-regular-48.json +15540 -0
- package/dist/cjs/src/data/index.d.ts +2 -0
- package/dist/cjs/src/data/index.d.ts.map +1 -0
- package/dist/cjs/src/data/index.js +18 -0
- package/dist/cjs/src/data/index.js.map +1 -0
- package/dist/cjs/src/index.d.ts +4 -0
- package/dist/cjs/src/index.d.ts.map +1 -0
- package/dist/cjs/src/index.js +20 -0
- package/dist/cjs/src/index.js.map +1 -0
- package/dist/esm/playground.d.ts +2 -0
- package/dist/esm/playground.d.ts.map +1 -0
- package/dist/esm/playground.js +37 -0
- package/dist/esm/playground.js.map +1 -0
- package/dist/esm/src/canvas/canvas.d.ts +41 -0
- package/dist/esm/src/canvas/canvas.d.ts.map +1 -0
- package/dist/esm/src/canvas/canvas.js +83 -0
- package/dist/esm/src/canvas/canvas.js.map +1 -0
- package/dist/esm/src/canvas/context-2d.d.ts +37 -0
- package/dist/esm/src/canvas/context-2d.d.ts.map +1 -0
- package/dist/esm/src/canvas/context-2d.js +245 -0
- package/dist/esm/src/canvas/context-2d.js.map +1 -0
- package/dist/esm/src/canvas/index.d.ts +2 -0
- package/dist/esm/src/canvas/index.d.ts.map +1 -0
- package/dist/esm/src/canvas/index.js +18 -0
- package/dist/esm/src/canvas/index.js.map +1 -0
- package/dist/esm/src/common/array.d.ts +40 -0
- package/dist/esm/src/common/array.d.ts.map +1 -0
- package/dist/esm/src/common/array.js +99 -0
- package/dist/esm/src/common/array.js.map +1 -0
- package/dist/esm/src/common/colors.d.ts +62 -0
- package/dist/esm/src/common/colors.d.ts.map +1 -0
- package/dist/esm/src/common/colors.js +93 -0
- package/dist/esm/src/common/colors.js.map +1 -0
- package/dist/esm/src/common/hash.d.ts +3 -0
- package/dist/esm/src/common/hash.d.ts.map +1 -0
- package/dist/esm/src/common/hash.js +44 -0
- package/dist/esm/src/common/hash.js.map +1 -0
- package/dist/esm/src/common/index.d.ts +7 -0
- package/dist/esm/src/common/index.d.ts.map +1 -0
- package/dist/esm/src/common/index.js +23 -0
- package/dist/esm/src/common/index.js.map +1 -0
- package/dist/esm/src/common/ppm.d.ts +2 -0
- package/dist/esm/src/common/ppm.d.ts.map +1 -0
- package/dist/esm/src/common/ppm.js +21 -0
- package/dist/esm/src/common/ppm.js.map +1 -0
- package/dist/esm/src/common/scalar.d.ts +27 -0
- package/dist/esm/src/common/scalar.d.ts.map +1 -0
- package/dist/esm/src/common/scalar.js +65 -0
- package/dist/esm/src/common/scalar.js.map +1 -0
- package/dist/esm/src/common/types.d.ts +9 -0
- package/dist/esm/src/common/types.d.ts.map +1 -0
- package/dist/esm/src/common/types.js +3 -0
- package/dist/esm/src/common/types.js.map +1 -0
- package/dist/esm/src/data/font/index.d.ts +2 -0
- package/dist/esm/src/data/font/index.d.ts.map +1 -0
- package/dist/esm/src/data/font/index.js +18 -0
- package/dist/esm/src/data/font/index.js.map +1 -0
- package/dist/esm/src/data/font/noto-mono-regular-48.d.ts +747 -0
- package/dist/esm/src/data/font/noto-mono-regular-48.d.ts.map +1 -0
- package/dist/esm/src/data/font/noto-mono-regular-48.js +15544 -0
- package/dist/esm/src/data/font/noto-mono-regular-48.js.map +1 -0
- package/dist/esm/src/data/font/noto-mono-regular-48.json +15540 -0
- package/dist/esm/src/data/index.d.ts +2 -0
- package/dist/esm/src/data/index.d.ts.map +1 -0
- package/dist/esm/src/data/index.js +18 -0
- package/dist/esm/src/data/index.js.map +1 -0
- package/dist/esm/src/index.d.ts +4 -0
- package/dist/esm/src/index.d.ts.map +1 -0
- package/dist/esm/src/index.js +20 -0
- package/dist/esm/src/index.js.map +1 -0
- package/package.json +43 -0
- package/playground.ts +41 -0
- package/pnpm-lock.yaml +352 -0
- package/render_font.py +98 -0
- package/src/canvas/canvas.ts +123 -0
- package/src/canvas/context-2d.ts +305 -0
- package/src/canvas/index.ts +1 -0
- package/src/common/array.ts +176 -0
- package/src/common/colors.ts +93 -0
- package/src/common/hash.ts +46 -0
- package/src/common/index.ts +6 -0
- package/src/common/ppm.ts +28 -0
- package/src/common/scalar.ts +72 -0
- package/src/common/types.ts +10 -0
- package/src/data/font/index.ts +1 -0
- package/src/data/font/noto-mono-regular-48.json +15540 -0
- package/src/data/font/noto-mono-regular-48.ts +15540 -0
- package/src/data/index.ts +1 -0
- package/src/index.ts +3 -0
- package/tsconfig.cjs.json +10 -0
- package/tsconfig.esm.json +10 -0
- package/tsconfig.json +23 -0
package/.gitignore
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/*.ppm
|
|
2
|
+
# Created by https://www.toptal.com/developers/gitignore/api/vim,emacs,yarn,node
|
|
3
|
+
# Edit at https://www.toptal.com/developers/gitignore?templates=vim,emacs,yarn,node
|
|
4
|
+
|
|
5
|
+
### Emacs ###
|
|
6
|
+
# -*- mode: gitignore; -*-
|
|
7
|
+
*~
|
|
8
|
+
\#*\#
|
|
9
|
+
/.emacs.desktop
|
|
10
|
+
/.emacs.desktop.lock
|
|
11
|
+
*.elc
|
|
12
|
+
auto-save-list
|
|
13
|
+
tramp
|
|
14
|
+
.\#*
|
|
15
|
+
|
|
16
|
+
# Org-mode
|
|
17
|
+
.org-id-locations
|
|
18
|
+
*_archive
|
|
19
|
+
|
|
20
|
+
# flymake-mode
|
|
21
|
+
*_flymake.*
|
|
22
|
+
|
|
23
|
+
# eshell files
|
|
24
|
+
/eshell/history
|
|
25
|
+
/eshell/lastdir
|
|
26
|
+
|
|
27
|
+
# elpa packages
|
|
28
|
+
/elpa/
|
|
29
|
+
|
|
30
|
+
# reftex files
|
|
31
|
+
*.rel
|
|
32
|
+
|
|
33
|
+
# AUCTeX auto folder
|
|
34
|
+
/auto/
|
|
35
|
+
|
|
36
|
+
# cask packages
|
|
37
|
+
.cask/
|
|
38
|
+
dist/
|
|
39
|
+
|
|
40
|
+
# Flycheck
|
|
41
|
+
flycheck_*.el
|
|
42
|
+
|
|
43
|
+
# server auth directory
|
|
44
|
+
/server/
|
|
45
|
+
|
|
46
|
+
# projectiles files
|
|
47
|
+
.projectile
|
|
48
|
+
|
|
49
|
+
# directory configuration
|
|
50
|
+
.dir-locals.el
|
|
51
|
+
|
|
52
|
+
# network security
|
|
53
|
+
/network-security.data
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
### Node ###
|
|
57
|
+
# Logs
|
|
58
|
+
logs
|
|
59
|
+
*.log
|
|
60
|
+
npm-debug.log*
|
|
61
|
+
yarn-debug.log*
|
|
62
|
+
yarn-error.log*
|
|
63
|
+
lerna-debug.log*
|
|
64
|
+
.pnpm-debug.log*
|
|
65
|
+
|
|
66
|
+
# Diagnostic reports (https://nodejs.org/api/report.html)
|
|
67
|
+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|
68
|
+
|
|
69
|
+
# Runtime data
|
|
70
|
+
pids
|
|
71
|
+
*.pid
|
|
72
|
+
*.seed
|
|
73
|
+
*.pid.lock
|
|
74
|
+
|
|
75
|
+
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
76
|
+
lib-cov
|
|
77
|
+
|
|
78
|
+
# Coverage directory used by tools like istanbul
|
|
79
|
+
coverage
|
|
80
|
+
*.lcov
|
|
81
|
+
|
|
82
|
+
# nyc test coverage
|
|
83
|
+
.nyc_output
|
|
84
|
+
|
|
85
|
+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
86
|
+
.grunt
|
|
87
|
+
|
|
88
|
+
# Bower dependency directory (https://bower.io/)
|
|
89
|
+
bower_components
|
|
90
|
+
|
|
91
|
+
# node-waf configuration
|
|
92
|
+
.lock-wscript
|
|
93
|
+
|
|
94
|
+
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
95
|
+
build/Release
|
|
96
|
+
|
|
97
|
+
# Dependency directories
|
|
98
|
+
node_modules/
|
|
99
|
+
jspm_packages/
|
|
100
|
+
|
|
101
|
+
# Snowpack dependency directory (https://snowpack.dev/)
|
|
102
|
+
web_modules/
|
|
103
|
+
|
|
104
|
+
# TypeScript cache
|
|
105
|
+
*.tsbuildinfo
|
|
106
|
+
|
|
107
|
+
# Optional npm cache directory
|
|
108
|
+
.npm
|
|
109
|
+
|
|
110
|
+
# Optional eslint cache
|
|
111
|
+
.eslintcache
|
|
112
|
+
|
|
113
|
+
# Optional stylelint cache
|
|
114
|
+
.stylelintcache
|
|
115
|
+
|
|
116
|
+
# Microbundle cache
|
|
117
|
+
.rpt2_cache/
|
|
118
|
+
.rts2_cache_cjs/
|
|
119
|
+
.rts2_cache_es/
|
|
120
|
+
.rts2_cache_umd/
|
|
121
|
+
|
|
122
|
+
# Optional REPL history
|
|
123
|
+
.node_repl_history
|
|
124
|
+
|
|
125
|
+
# Output of 'npm pack'
|
|
126
|
+
*.tgz
|
|
127
|
+
|
|
128
|
+
# Yarn Integrity file
|
|
129
|
+
.yarn-integrity
|
|
130
|
+
|
|
131
|
+
# dotenv environment variable files
|
|
132
|
+
.env
|
|
133
|
+
.env.development.local
|
|
134
|
+
.env.test.local
|
|
135
|
+
.env.production.local
|
|
136
|
+
.env.local
|
|
137
|
+
|
|
138
|
+
# parcel-bundler cache (https://parceljs.org/)
|
|
139
|
+
.cache
|
|
140
|
+
.parcel-cache
|
|
141
|
+
|
|
142
|
+
# Next.js build output
|
|
143
|
+
.next
|
|
144
|
+
out
|
|
145
|
+
|
|
146
|
+
# Nuxt.js build / generate output
|
|
147
|
+
.nuxt
|
|
148
|
+
dist
|
|
149
|
+
|
|
150
|
+
# Gatsby files
|
|
151
|
+
.cache/
|
|
152
|
+
# Comment in the public line in if your project uses Gatsby and not Next.js
|
|
153
|
+
# https://nextjs.org/blog/next-9-1#public-directory-support
|
|
154
|
+
# public
|
|
155
|
+
|
|
156
|
+
# vuepress build output
|
|
157
|
+
.vuepress/dist
|
|
158
|
+
|
|
159
|
+
# vuepress v2.x temp and cache directory
|
|
160
|
+
.temp
|
|
161
|
+
|
|
162
|
+
# Docusaurus cache and generated files
|
|
163
|
+
.docusaurus
|
|
164
|
+
|
|
165
|
+
# Serverless directories
|
|
166
|
+
.serverless/
|
|
167
|
+
|
|
168
|
+
# FuseBox cache
|
|
169
|
+
.fusebox/
|
|
170
|
+
|
|
171
|
+
# DynamoDB Local files
|
|
172
|
+
.dynamodb/
|
|
173
|
+
|
|
174
|
+
# TernJS port file
|
|
175
|
+
.tern-port
|
|
176
|
+
|
|
177
|
+
# Stores VSCode versions used for testing VSCode extensions
|
|
178
|
+
.vscode-test
|
|
179
|
+
|
|
180
|
+
# yarn v2
|
|
181
|
+
.yarn/cache
|
|
182
|
+
.yarn/unplugged
|
|
183
|
+
.yarn/build-state.yml
|
|
184
|
+
.yarn/install-state.gz
|
|
185
|
+
.pnp.*
|
|
186
|
+
|
|
187
|
+
### Node Patch ###
|
|
188
|
+
# Serverless Webpack directories
|
|
189
|
+
.webpack/
|
|
190
|
+
|
|
191
|
+
# Optional stylelint cache
|
|
192
|
+
|
|
193
|
+
# SvelteKit build / generate output
|
|
194
|
+
.svelte-kit
|
|
195
|
+
|
|
196
|
+
### Vim ###
|
|
197
|
+
# Swap
|
|
198
|
+
[._]*.s[a-v][a-z]
|
|
199
|
+
!*.svg # comment out if you don't need vector files
|
|
200
|
+
[._]*.sw[a-p]
|
|
201
|
+
[._]s[a-rt-v][a-z]
|
|
202
|
+
[._]ss[a-gi-z]
|
|
203
|
+
[._]sw[a-p]
|
|
204
|
+
|
|
205
|
+
# Session
|
|
206
|
+
Session.vim
|
|
207
|
+
Sessionx.vim
|
|
208
|
+
|
|
209
|
+
# Temporary
|
|
210
|
+
.netrwhist
|
|
211
|
+
# Auto-generated tag files
|
|
212
|
+
tags
|
|
213
|
+
# Persistent undo
|
|
214
|
+
[._]*.un~
|
|
215
|
+
|
|
216
|
+
### yarn ###
|
|
217
|
+
# https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored
|
|
218
|
+
|
|
219
|
+
.yarn/*
|
|
220
|
+
!.yarn/releases
|
|
221
|
+
!.yarn/patches
|
|
222
|
+
!.yarn/plugins
|
|
223
|
+
!.yarn/sdks
|
|
224
|
+
!.yarn/versions
|
|
225
|
+
|
|
226
|
+
# if you are NOT using Zero-installs, then:
|
|
227
|
+
# comment the following lines
|
|
228
|
+
!.yarn/cache
|
|
229
|
+
|
|
230
|
+
# and uncomment the following lines
|
|
231
|
+
# .pnp.*
|
|
232
|
+
|
|
233
|
+
# End of https://www.toptal.com/developers/gitignore/api/vim,emacs,yarn,node
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm build # compile to both ESM (dist/esm) and CJS (dist/cjs)
|
|
9
|
+
pnpm check # type-check without emitting (uses tsconfig.json)
|
|
10
|
+
pnpm test # run vitest
|
|
11
|
+
pnpm format # format src/ with prettier
|
|
12
|
+
|
|
13
|
+
# Run the playground script manually (no test infra needed)
|
|
14
|
+
npx tsx playground.ts
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Architecture
|
|
18
|
+
|
|
19
|
+
This is a **headless Canvas API emulator** — a TypeScript library that replicates the browser `CanvasRenderingContext2D` API for server-side rendering, outputting to PPM image files or raw pixel buffers.
|
|
20
|
+
|
|
21
|
+
### Key design conventions
|
|
22
|
+
|
|
23
|
+
- **All color values are normalized floats `[0, 1]`**, not `[0, 255]`. This applies to pixels stored in `Canvas.data` and all `V3`/`V4` color tuples.
|
|
24
|
+
- **Pixels are RGBA** arrays `[r, g, b, a]` stored flat in `Canvas.data`. The canvas always has 4 channels.
|
|
25
|
+
- `setAt` performs **alpha compositing** using `smoothstep`-based mixing between the existing pixel and the incoming one.
|
|
26
|
+
- Canvas supports both **pixel-space** (`at`, `setAt` using integer x/y) and **UV-space** (`atUV`, `setAtUV` using `[0,1]` coordinates).
|
|
27
|
+
|
|
28
|
+
### Module structure
|
|
29
|
+
|
|
30
|
+
- **`src/canvas/`** — Core canvas implementation
|
|
31
|
+
- `canvas.ts` — `Canvas` interface + `CanvasImpl` class (pixel buffer). `createCanvas(cfg)` is the main entry point.
|
|
32
|
+
- `context-2d.ts` — `CanvasContext2DImpl`: mimics `CanvasRenderingContext2D`. Maintains a `State` stack for `save()`/`restore()`. Paths are stored as flat pairs of points (`[p1, p2, p3, p4, ...]`) and consumed two at a time for line segments in `stroke()`. `fill()` uses a scanline ray-casting algorithm.
|
|
33
|
+
- Font rendering (`drawChar`, `fillText`) uses bitmap data from `src/data/font/noto-mono-regular-48.json` — a 48×48px glyph atlas keyed by char code.
|
|
34
|
+
|
|
35
|
+
- **`src/common/`** — Shared math & utilities
|
|
36
|
+
- `types.ts` — Vector aliases: `V2`, `V3`, `V4`
|
|
37
|
+
- `array.ts` — Vector math: `add`, `sub`, `mul`, `div`, `scale`, `dot`, `cross`, `normalize`, `distance`, `toBatched`, `range`, etc.
|
|
38
|
+
- `scalar.ts` — Scalar math: `clamp`, `lerp`, `remap`, `smoothstep`, `smin`, `smax`, `fract`, `amod`, `sigmoid`, etc.
|
|
39
|
+
- `colors.ts` — `toRGB(color: string): V3` parses CSS named colors, `#RGB`/`#RRGGBB` hex, and `rgb()`/`rgba()` strings into normalized `[0,1]` triples.
|
|
40
|
+
- `ppm.ts` — `createPPM(width, height, pixels)` serializes RGB pixels to a P3 PPM string.
|
|
41
|
+
|
|
42
|
+
### Dual build output
|
|
43
|
+
|
|
44
|
+
`tsconfig.esm.json` → `dist/esm` (ES modules, NodeNext)
|
|
45
|
+
`tsconfig.cjs.json` → `dist/cjs` (CommonJS)
|
|
46
|
+
Both exclude `*.test.ts` and `*.sample.ts` files.
|
|
47
|
+
|
|
48
|
+
### Typical usage pattern
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { createCanvas, createPPM } from 'canvas-emulator';
|
|
52
|
+
import fs from 'fs';
|
|
53
|
+
|
|
54
|
+
const canvas = createCanvas({ width: 512, height: 512 });
|
|
55
|
+
const ctx = canvas.getContext2D();
|
|
56
|
+
|
|
57
|
+
ctx.fillStyle = 'blue';
|
|
58
|
+
ctx.fillRect(10, 10, 100, 100);
|
|
59
|
+
|
|
60
|
+
fs.writeFileSync('out.ppm', createPPM(canvas.width, canvas.height, canvas.renderRGB()));
|
|
61
|
+
```
|
package/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# canvas-emulator
|
|
2
|
+
|
|
3
|
+
A headless Canvas 2D rendering library for Node.js. Draw shapes, text, and paths using a familiar `CanvasRenderingContext2D`-style API, then export to PPM image files or raw pixel buffers — no browser required.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add canvas-emulator
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { createCanvas, createPPM } from 'canvas-emulator';
|
|
15
|
+
import fs from 'fs';
|
|
16
|
+
|
|
17
|
+
const canvas = createCanvas({ width: 512, height: 512 });
|
|
18
|
+
const ctx = canvas.getContext2D();
|
|
19
|
+
|
|
20
|
+
// Draw a filled rectangle
|
|
21
|
+
ctx.fillStyle = 'blue';
|
|
22
|
+
ctx.fillRect(50, 50, 200, 150);
|
|
23
|
+
|
|
24
|
+
// Draw a circle
|
|
25
|
+
ctx.save();
|
|
26
|
+
ctx.beginPath();
|
|
27
|
+
ctx.arc(256, 256, 80, 0);
|
|
28
|
+
ctx.closePath();
|
|
29
|
+
ctx.fillStyle = '#ff6600';
|
|
30
|
+
ctx.fill();
|
|
31
|
+
ctx.restore();
|
|
32
|
+
|
|
33
|
+
// Render text
|
|
34
|
+
ctx.fillStyle = 'white';
|
|
35
|
+
ctx.fillText('Hello!', 100, 100, 48);
|
|
36
|
+
|
|
37
|
+
// Write to a PPM image file
|
|
38
|
+
fs.writeFileSync('output.ppm', createPPM(canvas.width, canvas.height, canvas.renderRGB()));
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Open PPM files with GIMP, Preview (macOS), or convert them with ImageMagick (`convert output.ppm output.png`).
|
|
42
|
+
|
|
43
|
+
## API
|
|
44
|
+
|
|
45
|
+
### Canvas
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
const canvas = createCanvas({ width: number, height: number });
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
| Member | Description |
|
|
52
|
+
|---|---|
|
|
53
|
+
| `canvas.width / .height` | Dimensions in pixels |
|
|
54
|
+
| `canvas.data` | Raw flat RGBA array, values normalized to `[0, 1]` |
|
|
55
|
+
| `canvas.at([x, y])` | Read pixel at pixel-space coordinates |
|
|
56
|
+
| `canvas.atUV([u, v])` | Read pixel at UV coordinates (`[0,1]` range) |
|
|
57
|
+
| `canvas.setAt([x, y], pixel)` | Write pixel (alpha-composited) |
|
|
58
|
+
| `canvas.each(fn)` | Iterate over every pixel with `(pos, uv)` |
|
|
59
|
+
| `canvas.renderRGB()` | Returns `[r, g, b][]` — suitable for `createPPM` |
|
|
60
|
+
| `canvas.renderRGBA()` | Returns `[r, g, b, a][]` |
|
|
61
|
+
| `canvas.getContext2D()` | Returns a `CanvasContext2D` drawing context |
|
|
62
|
+
|
|
63
|
+
> **Note:** All color channel values are normalized floats in `[0, 1]`, not `[0, 255]`.
|
|
64
|
+
|
|
65
|
+
### Context 2D
|
|
66
|
+
|
|
67
|
+
The context closely mirrors the browser [`CanvasRenderingContext2D`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D):
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
const ctx = canvas.getContext2D();
|
|
71
|
+
|
|
72
|
+
ctx.fillStyle = 'red'; // CSS color name, #hex, or rgb()/rgba()
|
|
73
|
+
ctx.strokeStyle = '#00ff00';
|
|
74
|
+
|
|
75
|
+
ctx.save(); // push state
|
|
76
|
+
ctx.restore(); // pop state
|
|
77
|
+
|
|
78
|
+
ctx.fillRect(x, y, w, h);
|
|
79
|
+
ctx.strokeRect(x, y, w, h);
|
|
80
|
+
ctx.clearRect(x, y, w, h);
|
|
81
|
+
|
|
82
|
+
ctx.beginPath();
|
|
83
|
+
ctx.moveTo(x, y);
|
|
84
|
+
ctx.lineTo(x, y);
|
|
85
|
+
ctx.arc(x, y, radius, startAngle);
|
|
86
|
+
ctx.rect(x, y, w, h);
|
|
87
|
+
ctx.closePath();
|
|
88
|
+
ctx.fill();
|
|
89
|
+
ctx.stroke();
|
|
90
|
+
|
|
91
|
+
ctx.fillText(text, x, y);
|
|
92
|
+
ctx.fillText(text, x, y, fontSize); // fontSize in pixels (default: 48)
|
|
93
|
+
ctx.measureText(text); // returns { width }
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Supported color formats:** CSS named colors (`red`, `blue`, `coral`, etc.), `#RGB`, `#RRGGBB`, `rgb(r, g, b)`, `rgba(r, g, b, a)`.
|
|
97
|
+
|
|
98
|
+
### Utilities
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import { createPPM, toRGB, clamp, lerp, remap, smoothstep } from 'canvas-emulator';
|
|
102
|
+
|
|
103
|
+
// PPM export
|
|
104
|
+
createPPM(width, height, pixels); // pixels: [r, g, b][] normalized to [0,1]
|
|
105
|
+
|
|
106
|
+
// Color parsing
|
|
107
|
+
toRGB('coral'); // → [1, 0.498, 0.314]
|
|
108
|
+
toRGB('#ff8800'); // → [1, 0.533, 0]
|
|
109
|
+
|
|
110
|
+
// Math helpers
|
|
111
|
+
clamp(x, min, max);
|
|
112
|
+
lerp(from, to, t);
|
|
113
|
+
remap(x, [inMin, inMax], [outMin, outMax]);
|
|
114
|
+
smoothstep(edge0, edge1, value);
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Vector math (`add`, `sub`, `mul`, `div`, `scale`, `dot`, `normalize`, `distance`, etc.) is also exported for working directly with pixel data.
|
|
118
|
+
|
|
119
|
+
## Development
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
pnpm build # compile (outputs dist/esm and dist/cjs)
|
|
123
|
+
pnpm check # type-check only
|
|
124
|
+
pnpm test # run tests
|
|
125
|
+
pnpm format # format source files
|
|
126
|
+
|
|
127
|
+
npx tsx playground.ts # run the playground script
|
|
128
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playground.d.ts","sourceRoot":"","sources":["../../playground.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const src_1 = require("./src");
|
|
7
|
+
const canvas_1 = require("./src/canvas/canvas");
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const canvas = (0, canvas_1.createCanvas)({
|
|
10
|
+
width: 512,
|
|
11
|
+
height: 512
|
|
12
|
+
});
|
|
13
|
+
const ctx = canvas.getContext2D();
|
|
14
|
+
//ctx.save();
|
|
15
|
+
//ctx.beginPath();
|
|
16
|
+
//ctx.lineTo(canvas.width, canvas.height);
|
|
17
|
+
//ctx.closePath();
|
|
18
|
+
//ctx.stroke();
|
|
19
|
+
//ctx.restore();
|
|
20
|
+
//ctx.save();
|
|
21
|
+
//ctx.beginPath();
|
|
22
|
+
//ctx.arc(512/2, 512/2, 64, 0);
|
|
23
|
+
//ctx.closePath();
|
|
24
|
+
//ctx.fillStyle = 'purple';
|
|
25
|
+
//ctx.fill();
|
|
26
|
+
//ctx.restore();
|
|
27
|
+
//
|
|
28
|
+
//ctx.save();
|
|
29
|
+
//ctx.beginPath();
|
|
30
|
+
//ctx.rect((512/2)-16, (512/2)-16, 32, 32);
|
|
31
|
+
//ctx.closePath();
|
|
32
|
+
//ctx.fill();
|
|
33
|
+
//ctx.restore();
|
|
34
|
+
ctx.fillText('hello', 0, 512 / 4, 128);
|
|
35
|
+
const ppm = (0, src_1.createPPM)(canvas.width, canvas.height, canvas.renderRGB());
|
|
36
|
+
fs_1.default.writeFileSync('image.ppm', ppm, { encoding: 'utf-8' });
|
|
37
|
+
//# sourceMappingURL=playground.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playground.js","sourceRoot":"","sources":["../../playground.ts"],"names":[],"mappings":";;;;;AAAA,+BAAkC;AAClC,gDAAmD;AACnD,4CAAoB;AAEpB,MAAM,MAAM,GAAG,IAAA,qBAAY,EAAC;IAC1B,KAAK,EAAE,GAAG;IACV,MAAM,EAAE,GAAG;CACZ,CAAC,CAAC;AAEH,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;AAGlC,aAAa;AACb,kBAAkB;AAClB,0CAA0C;AAC1C,kBAAkB;AAClB,eAAe;AACf,gBAAgB;AAIhB,aAAa;AACb,kBAAkB;AAClB,+BAA+B;AAC/B,kBAAkB;AAClB,2BAA2B;AAC3B,aAAa;AACb,gBAAgB;AAChB,EAAE;AACF,aAAa;AACb,kBAAkB;AAClB,2CAA2C;AAC3C,kBAAkB;AAClB,aAAa;AACb,gBAAgB;AAEhB,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,GAAG,GAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAErC,MAAM,GAAG,GAAG,IAAA,eAAS,EAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;AAEvE,YAAE,CAAC,aAAa,CAAC,WAAW,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type CanvasContext2D } from "./context-2d";
|
|
2
|
+
export type Pixel = [number, number, number, number];
|
|
3
|
+
export type Point = [number, number];
|
|
4
|
+
export interface Canvas {
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
channels: number;
|
|
8
|
+
data: Array<number>;
|
|
9
|
+
indexAt(p: Point): number;
|
|
10
|
+
at(p: Point): Pixel;
|
|
11
|
+
atUV(p: Point): Pixel;
|
|
12
|
+
setAt(p: Point, px: Pixel | number): void;
|
|
13
|
+
setAtUV(p: Point, px: Pixel | number): void;
|
|
14
|
+
each(fn: (pos: Point, uv: Point) => void): void;
|
|
15
|
+
renderRGBA(): Array<Pixel>;
|
|
16
|
+
renderRGB(): Array<[number, number, number]>;
|
|
17
|
+
getContext2D(): CanvasContext2D;
|
|
18
|
+
}
|
|
19
|
+
export type CanvasConfig = {
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
};
|
|
23
|
+
export declare class CanvasImpl implements Canvas {
|
|
24
|
+
width: number;
|
|
25
|
+
height: number;
|
|
26
|
+
channels: 4;
|
|
27
|
+
data: Array<number>;
|
|
28
|
+
private readonly length;
|
|
29
|
+
constructor(cfg: CanvasConfig);
|
|
30
|
+
indexAt(p: Point): number;
|
|
31
|
+
at(p: Point): Pixel;
|
|
32
|
+
atUV(p: Point): Pixel;
|
|
33
|
+
setAt(p: Point, px: Pixel | number): void;
|
|
34
|
+
setAtUV(p: Point, px: Pixel | number): void;
|
|
35
|
+
each(fn: (pos: Point, uv: Point) => void): void;
|
|
36
|
+
renderRGBA(): Array<Pixel>;
|
|
37
|
+
renderRGB(): Array<[number, number, number]>;
|
|
38
|
+
getContext2D(): CanvasContext2D;
|
|
39
|
+
}
|
|
40
|
+
export declare const createCanvas: (cfg: CanvasConfig) => Canvas;
|
|
41
|
+
//# sourceMappingURL=canvas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas.d.ts","sourceRoot":"","sources":["../../../../src/canvas/canvas.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAEzE,MAAM,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AACrD,MAAM,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAErC,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAEpB,OAAO,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAC1B,EAAE,CAAC,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IACpB,IAAI,CAAC,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IAEtB,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI,CAAC;IAC1C,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI,CAAC;IAE5C,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IAEhD,UAAU,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;IAC3B,SAAS,IAAI,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAE7C,YAAY,IAAI,eAAe,CAAC;CACjC;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,qBAAa,UAAW,YAAW,MAAM;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,CAAC,CAAK;IAChB,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAEpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,GAAG,EAAE,YAAY;IAQ7B,OAAO,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM;IAMzB,EAAE,CAAC,CAAC,EAAE,KAAK,GAAG,KAAK;IAKnB,IAAI,CAAC,CAAC,EAAE,KAAK,GAAG,KAAK;IAMrB,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI;IAiBzC,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI;IAM3C,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;IAU/C,UAAU,IAAI,KAAK,CAAC,KAAK,CAAC;IAI1B,SAAS,IAAI,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAW5C,YAAY,IAAI,eAAe;CAGhC;AAED,eAAO,MAAM,YAAY,GAAI,KAAK,YAAY,KAAG,MAEhD,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createCanvas = exports.CanvasImpl = void 0;
|
|
4
|
+
const array_1 = require("../common/array");
|
|
5
|
+
const scalar_1 = require("../common/scalar");
|
|
6
|
+
const context_2d_1 = require("./context-2d");
|
|
7
|
+
class CanvasImpl {
|
|
8
|
+
width;
|
|
9
|
+
height;
|
|
10
|
+
channels = 4;
|
|
11
|
+
data;
|
|
12
|
+
length;
|
|
13
|
+
constructor(cfg) {
|
|
14
|
+
const { width, height } = cfg;
|
|
15
|
+
this.width = width;
|
|
16
|
+
this.height = height;
|
|
17
|
+
this.length = width * height * this.channels;
|
|
18
|
+
this.data = (0, array_1.range)(this.length).fill(0);
|
|
19
|
+
}
|
|
20
|
+
indexAt(p) {
|
|
21
|
+
const x = Math.floor(p[0]);
|
|
22
|
+
const y = Math.floor(p[1]);
|
|
23
|
+
return (0, scalar_1.clamp)((y * this.width + x) * this.channels, 0, this.length - 1);
|
|
24
|
+
}
|
|
25
|
+
at(p) {
|
|
26
|
+
const idx = this.indexAt(p);
|
|
27
|
+
return this.data.slice(idx, idx + this.channels);
|
|
28
|
+
}
|
|
29
|
+
atUV(p) {
|
|
30
|
+
const x = p[0] * this.width;
|
|
31
|
+
const y = p[1] * this.height;
|
|
32
|
+
return this.at([x, y]);
|
|
33
|
+
}
|
|
34
|
+
setAt(p, px) {
|
|
35
|
+
const idx = this.indexAt(p);
|
|
36
|
+
const nextAlpha = typeof px === "number" ? 1.0 : px[3];
|
|
37
|
+
const current = this.at(p);
|
|
38
|
+
const currentAlpha = current[3];
|
|
39
|
+
const nextData = typeof px === "number" ? [px, px, px, px] : px;
|
|
40
|
+
const mixCurrent = (0, scalar_1.smoothstep)(0, 1, currentAlpha - nextAlpha);
|
|
41
|
+
const mixNext = (0, scalar_1.smoothstep)(0, 1, nextAlpha);
|
|
42
|
+
for (let i = 0; i < nextData.length; i++) {
|
|
43
|
+
this.data[idx + i] =
|
|
44
|
+
this.data[idx + i] * mixCurrent + nextData[i] * mixNext;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
setAtUV(p, px) {
|
|
48
|
+
const x = p[0] * this.width;
|
|
49
|
+
const y = p[1] * this.height;
|
|
50
|
+
return this.setAt([x, y], px);
|
|
51
|
+
}
|
|
52
|
+
each(fn) {
|
|
53
|
+
for (let y = 0; y < this.height; y++) {
|
|
54
|
+
for (let x = 0; x < this.width; x++) {
|
|
55
|
+
const p = [x, y];
|
|
56
|
+
const uv = [x / this.width, y / this.height];
|
|
57
|
+
fn(p, uv);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
renderRGBA() {
|
|
62
|
+
return (0, array_1.toBatched)(this.data, this.channels, 0);
|
|
63
|
+
}
|
|
64
|
+
renderRGB() {
|
|
65
|
+
const pixels = [];
|
|
66
|
+
for (let i = 0; i < this.data.length; i += this.channels) {
|
|
67
|
+
const r = this.data[i];
|
|
68
|
+
const g = this.data[i + 1];
|
|
69
|
+
const b = this.data[i + 2];
|
|
70
|
+
pixels.push([r, g, b]);
|
|
71
|
+
}
|
|
72
|
+
return pixels;
|
|
73
|
+
}
|
|
74
|
+
getContext2D() {
|
|
75
|
+
return new context_2d_1.CanvasContext2DImpl(this);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
exports.CanvasImpl = CanvasImpl;
|
|
79
|
+
const createCanvas = (cfg) => {
|
|
80
|
+
return new CanvasImpl(cfg);
|
|
81
|
+
};
|
|
82
|
+
exports.createCanvas = createCanvas;
|
|
83
|
+
//# sourceMappingURL=canvas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas.js","sourceRoot":"","sources":["../../../../src/canvas/canvas.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type Canvas } from "./canvas";
|
|
2
|
+
export type TextMetrics = {
|
|
3
|
+
width: number;
|
|
4
|
+
};
|
|
5
|
+
export type CanvasContext2D = CanvasContext2DImpl;
|
|
6
|
+
export declare class CanvasContext2DImpl {
|
|
7
|
+
canvas: Canvas;
|
|
8
|
+
private stack;
|
|
9
|
+
constructor(canvas: Canvas);
|
|
10
|
+
private get state();
|
|
11
|
+
get fillStyle(): string;
|
|
12
|
+
set fillStyle(value: string);
|
|
13
|
+
get strokeStyle(): string;
|
|
14
|
+
set strokeStyle(value: string);
|
|
15
|
+
save(): void;
|
|
16
|
+
restore(): void;
|
|
17
|
+
moveTo(x: number, y: number): void;
|
|
18
|
+
lineTo(x: number, y: number): void;
|
|
19
|
+
arc(x: number, y: number, radius: number, startAngle: number): void;
|
|
20
|
+
rect(x: number, y: number, width: number, height: number): void;
|
|
21
|
+
fill(): void;
|
|
22
|
+
stroke(): void;
|
|
23
|
+
strokeRect(x: number, y: number, width: number, height: number): void;
|
|
24
|
+
fillRect(x: number, y: number, width: number, height: number): void;
|
|
25
|
+
clearRect(x: number, y: number, width: number, height: number): void;
|
|
26
|
+
private drawChar;
|
|
27
|
+
fillText(text: string, x: number, y: number): void;
|
|
28
|
+
fillText(text: string, x: number, y: number, maxWidth: number): void;
|
|
29
|
+
fillText(text: string, x: number, y: number, maxWidth: undefined): void;
|
|
30
|
+
strokeText(text: string, x: number, y: number): void;
|
|
31
|
+
strokeText(text: string, x: number, y: number, maxWidth: number): void;
|
|
32
|
+
strokeText(text: string, x: number, y: number, maxWidth: undefined): void;
|
|
33
|
+
measureText(text: string): TextMetrics;
|
|
34
|
+
beginPath(): void;
|
|
35
|
+
closePath(): void;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=context-2d.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-2d.d.ts","sourceRoot":"","sources":["../../../../src/canvas/context-2d.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC;AAKvC,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAsDF,MAAM,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAElD,qBAAa,mBAAmB;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,KAAK,CAA+B;gBAEhC,MAAM,EAAE,MAAM;IAI1B,OAAO,KAAK,KAAK,GAIhB;IAED,IAAI,SAAS,IAAI,MAAM,CAEtB;IACD,IAAI,SAAS,CAAC,KAAK,EAAE,MAAM,EAE1B;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IACD,IAAI,WAAW,CAAC,KAAK,EAAE,MAAM,EAE5B;IAED,IAAI;IAIJ,OAAO,IAAI,IAAI;IAIf,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAIlC,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAKlC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAkBnE,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAe/D,IAAI,IAAI,IAAI;IAwCZ,MAAM,IAAI,IAAI;IAgCd,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAKrE,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAKnE,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAQpE,OAAO,CAAC,QAAQ;IA2ChB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IACpE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,GAAG,IAAI;IAUvE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IACpD,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IACtE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,GAAG,IAAI;IAKzE,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW;IAItC,SAAS,IAAI,IAAI;IAGjB,SAAS,IAAI,IAAI;CAGlB"}
|