castle-web-cli 0.4.83 → 0.4.85

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.
Files changed (85) hide show
  1. package/dist/agent-failures.d.ts +17 -0
  2. package/dist/agent-failures.js +151 -0
  3. package/dist/agent.d.ts +26 -0
  4. package/dist/agent.js +317 -74
  5. package/dist/ide.js +35 -13
  6. package/dist/native/loop.js +35 -0
  7. package/dist/native/openrouter.d.ts +7 -0
  8. package/dist/native/openrouter.js +25 -1
  9. package/dist/native/types.d.ts +2 -0
  10. package/dist/native/types.js +0 -38
  11. package/dist/openrouter-catalog.d.ts +28 -0
  12. package/dist/openrouter-catalog.js +299 -0
  13. package/dist/shell/assets/{index-C9Zhmien.js → index-BJLaUTJE.js} +60 -58
  14. package/dist/shell/assets/{index-BMkQt27u.css → index-DonnH--m.css} +1 -1
  15. package/dist/shell/index.html +2 -2
  16. package/kits/physics-2d/.prettierrc +8 -0
  17. package/kits/physics-2d/CLAUDE.md +329 -0
  18. package/kits/physics-2d/behaviors/Camera.jsx +43 -0
  19. package/kits/physics-2d/behaviors/Collider.jsx +199 -0
  20. package/kits/physics-2d/behaviors/Goal.jsx +29 -0
  21. package/kits/physics-2d/behaviors/Layout.jsx +53 -0
  22. package/kits/physics-2d/behaviors/Sprite.jsx +352 -0
  23. package/kits/physics-2d/behaviors/tint.js +47 -0
  24. package/kits/physics-2d/blueprints/ball.scene +14 -0
  25. package/kits/physics-2d/blueprints/block.scene +12 -0
  26. package/kits/physics-2d/blueprints/cauldron.scene +18 -0
  27. package/kits/physics-2d/blueprints/crate.scene +14 -0
  28. package/kits/physics-2d/blueprints/goal.scene +12 -0
  29. package/kits/physics-2d/castle.json +13 -0
  30. package/kits/physics-2d/docs/pxart-format.md +377 -0
  31. package/kits/physics-2d/drawings/block.pxart +25 -0
  32. package/kits/physics-2d/drawings/cauldron.pxart +113 -0
  33. package/kits/physics-2d/editors/BlueprintLibrary.jsx +247 -0
  34. package/kits/physics-2d/editors/ErrorBoundary.jsx +59 -0
  35. package/kits/physics-2d/editors/PlayOnly.jsx +31 -0
  36. package/kits/physics-2d/editors/PxArtEditor.jsx +954 -0
  37. package/kits/physics-2d/editors/SceneEditor.jsx +1681 -0
  38. package/kits/physics-2d/editors/SelectionOverlay.jsx +909 -0
  39. package/kits/physics-2d/editors/SingleEditor.jsx +122 -0
  40. package/kits/physics-2d/editors/behaviorRegistry.js +30 -0
  41. package/kits/physics-2d/editors/editorHistory.js +157 -0
  42. package/kits/physics-2d/editors/inspectorSheet.js +13 -0
  43. package/kits/physics-2d/editors/pixelCanvas.js +11 -0
  44. package/kits/physics-2d/editors/pixelEditorChrome.jsx +74 -0
  45. package/kits/physics-2d/editors/pixelGeometry.js +140 -0
  46. package/kits/physics-2d/editors/pixelInspector.jsx +633 -0
  47. package/kits/physics-2d/editors/pxArtEditorModel.js +732 -0
  48. package/kits/physics-2d/editors/pxArtPlayback.js +92 -0
  49. package/kits/physics-2d/editors/pxArtTimeline.jsx +752 -0
  50. package/kits/physics-2d/editors/pxArtTimeline.module.css +506 -0
  51. package/kits/physics-2d/editors/pxArtTools.js +232 -0
  52. package/kits/physics-2d/editors/useArtboardFit.js +102 -0
  53. package/kits/physics-2d/engine/ScenePlayer.jsx +196 -0
  54. package/kits/physics-2d/engine/SceneUI.jsx +59 -0
  55. package/kits/physics-2d/engine/assets.js +15 -0
  56. package/kits/physics-2d/engine/autoInspector.jsx +70 -0
  57. package/kits/physics-2d/engine/blueprint.js +521 -0
  58. package/kits/physics-2d/engine/collider.js +196 -0
  59. package/kits/physics-2d/engine/files.js +117 -0
  60. package/kits/physics-2d/engine/liveReload.js +88 -0
  61. package/kits/physics-2d/engine/pxart.js +1032 -0
  62. package/kits/physics-2d/engine/pxartSmooth.js +222 -0
  63. package/kits/physics-2d/engine/scene.js +686 -0
  64. package/kits/physics-2d/engine/spriteGeometry.js +32 -0
  65. package/kits/physics-2d/engine/ui.jsx +688 -0
  66. package/kits/physics-2d/engine/ui.module.css +2287 -0
  67. package/kits/physics-2d/eslint.config.js +71 -0
  68. package/kits/physics-2d/index.html +24 -0
  69. package/kits/physics-2d/main.jsx +24 -0
  70. package/kits/physics-2d/package-lock.json +2706 -0
  71. package/kits/physics-2d/package.json +42 -0
  72. package/kits/physics-2d/physics/PhysicsSystem.js +290 -0
  73. package/kits/physics-2d/physics/behaviors/AnalogStick.jsx +101 -0
  74. package/kits/physics-2d/physics/behaviors/Draggable.jsx +79 -0
  75. package/kits/physics-2d/physics/behaviors/RigidBody.jsx +55 -0
  76. package/kits/physics-2d/physics/behaviors/Slingshot.jsx +118 -0
  77. package/kits/physics-2d/physics/controls.js +79 -0
  78. package/kits/physics-2d/physics/index.js +26 -0
  79. package/kits/physics-2d/physics/matterBridge.js +126 -0
  80. package/kits/physics-2d/pnpm-lock.yaml +1761 -0
  81. package/kits/physics-2d/scenes/main.scene +12 -0
  82. package/kits/physics-2d/scenes/sandbox.scene +13 -0
  83. package/kits/physics-2d/scripts/draw.mjs +121 -0
  84. package/kits/physics-2d/vite.config.js +1 -0
  85. package/package.json +1 -1
@@ -0,0 +1,222 @@
1
+ // ============================================================================
2
+ // "Smooth" (Animal-Crossing-style) rendering for `.pxart` sprites.
3
+ // ============================================================================
4
+ //
5
+ // Sprites with a file-level `cornerRadius` > 0 (see pxart.js /
6
+ // docs/pxart-format.md) render through `renderSmoothSpriteFrame` instead of
7
+ // the normal 1px/cell `renderSpriteFrame`.
8
+ //
9
+ // This is a LOCAL, per-pixel kernel filter — the same shape of algorithm as
10
+ // Animal Crossing's actual smoothing (xBRZ-style template matching), not the
11
+ // global boundary-trace-and-round approach this file used to implement. That
12
+ // approach traced each region's FULL pixel-boundary loop and could detect
13
+ // long straight/staircase runs across the whole loop; it looked fine on
14
+ // blocky shapes but flattened organic curves it decided were "too regular",
15
+ // which isn't fixable by tuning since the run detection itself is the
16
+ // problem. This version never looks past a pixel's immediate 3x3
17
+ // neighborhood, so there is no run/regularity detection to mis-fire — it
18
+ // physically cannot flatten a curve, because it has no notion of a curve at
19
+ // all, only of each corner in isolation.
20
+ //
21
+ // Approach, per source pixel P:
22
+ // 1. Composite the frame normally (`renderSpriteFrame` — this already
23
+ // handles layer visibility/opacity/blend), then read back the native
24
+ // resolution raster. Regions are exact-RGBA-equality color runs, same as
25
+ // before.
26
+ // 2. Supersample: P gets its own `scale` x `scale` block of the output
27
+ // canvas (plain grid subdivision — every output pixel belongs to
28
+ // exactly one source pixel's block, so there is no possibility of a
29
+ // gap or overlap between neighboring pixels' rendering).
30
+ // 3. Fill P's whole block with its own color, then independently classify
31
+ // each of P's 4 corners against ONLY the 3 pixels touching that corner
32
+ // (2 edge-adjacent neighbors + 1 diagonal) and, for genuine convex
33
+ // corners, paint a `cornerRadius`-sized quarter-circle "cut" over that
34
+ // corner revealing the relevant neighbor's color (see `cornerFill`).
35
+ // Because every pixel only ever paints within its OWN block, this recoloring
36
+ // can never create a gap: it's the same guarantee a supersampled nearest-
37
+ // neighbor render already has, just with a softened corner instead of a hard
38
+ // one.
39
+ //
40
+ // Kept as a sibling of pxart.js (rather than inside it) so the format
41
+ // parser/serializer stays focused on the on-disk shape.
42
+ // ============================================================================
43
+
44
+ import { MAX_CORNER_RADIUS, renderSpriteFrame } from './pxart';
45
+
46
+ export const DEFAULT_SMOOTH_SCALE = 8;
47
+
48
+ // Fallback only for a caller that omits `cornerRadius` entirely; every real
49
+ // caller passes the sprite's own file-level `cornerRadius` value (see
50
+ // docs/pxart-format.md and Sprite.jsx/PxArtEditor.jsx), which is how the
51
+ // corner radius ends up being a portable, per-sprite part of the format
52
+ // rather than a fixed constant every smooth sprite is stuck with.
53
+ const FALLBACK_CORNER_RADIUS = 0.25;
54
+
55
+ /** Render one frame of a Sprite with locally corner-rounded fills,
56
+ * supersampled into `canvas` (sized to width*scale x height*scale). Reuses
57
+ * `renderSpriteFrame` for compositing (layers, opacity, visibility, blend),
58
+ * so those keep working unchanged. `cornerRadius` is in native-pixel units,
59
+ * clamped to `MAX_CORNER_RADIUS` (two cuts on the same edge must not
60
+ * overlap). */
61
+ export function renderSmoothSpriteFrame(
62
+ sprite,
63
+ frameIndex,
64
+ canvas,
65
+ { scale = DEFAULT_SMOOTH_SCALE, cornerRadius = FALLBACK_CORNER_RADIUS } = {}
66
+ ) {
67
+ const clampedRadius = Math.min(MAX_CORNER_RADIUS, Math.max(0, cornerRadius));
68
+ const { width, height } = sprite.resolution;
69
+ canvas.width = Math.max(1, Math.round(width * scale));
70
+ canvas.height = Math.max(1, Math.round(height * scale));
71
+ const ctx = canvas.getContext('2d');
72
+ if (!ctx) return;
73
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
74
+ if (width <= 0 || height <= 0) return;
75
+
76
+ const native = document.createElement('canvas');
77
+ renderSpriteFrame(sprite, frameIndex, native);
78
+ const nctx = native.getContext('2d');
79
+ const data = nctx?.getImageData(0, 0, width, height).data;
80
+ if (!data) return;
81
+
82
+ // null = out of canvas OR fully transparent; both read as "not this pixel's
83
+ // color" to every classification below, same as the old mask's treatment
84
+ // of out-of-canvas/transparent as background.
85
+ const colorAt = (x, y) => {
86
+ if (x < 0 || x >= width || y < 0 || y >= height) return null;
87
+ const i = (y * width + x) * 4;
88
+ const a = data[i + 3];
89
+ return a === 0 ? null : `${data[i]},${data[i + 1]},${data[i + 2]},${a}`;
90
+ };
91
+
92
+ ctx.save();
93
+ ctx.scale(scale, scale);
94
+ // Every pixel is processed, including transparent ones: a fully-enclosed
95
+ // transparent "hole" is, from its own corners' point of view, exactly the
96
+ // same kind of convex corner as an opaque pixel poking out of a
97
+ // background — it needs to cut (and round) its OWN corners the same way,
98
+ // or an enclosed 1px hole would stay a hard square forever (its opaque
99
+ // neighbors never round toward it, by the same-neighbor rule below).
100
+ for (let y = 0; y < height; y++) {
101
+ for (let x = 0; x < width; x++) drawPixelBlock(ctx, colorAt, x, y, colorAt(x, y), clampedRadius);
102
+ }
103
+ ctx.restore();
104
+ }
105
+
106
+ // ---------------------------------------------------------------------------
107
+ // per-pixel local corner kernel
108
+ // ---------------------------------------------------------------------------
109
+
110
+ const NO_CUT = undefined;
111
+
112
+ // Fill pixel (x, y)'s own unit square [x, x+1] x [y, y+1] with `color` (a
113
+ // no-op when `color` is null — transparent, nothing to fill), then paint a
114
+ // small rounded cut over each of its 4 corners that qualifies (see
115
+ // `cornerFill`). Uses ONLY the 3x3 neighborhood of (x, y) — genuinely local,
116
+ // unlike the old global loop trace.
117
+ function drawPixelBlock(ctx, colorAt, x, y, color, cornerRadius) {
118
+ const north = colorAt(x, y - 1);
119
+ const south = colorAt(x, y + 1);
120
+ const west = colorAt(x - 1, y);
121
+ const east = colorAt(x + 1, y);
122
+
123
+ const cuts = [
124
+ ['TL', cornerFill(color, west, north, colorAt(x - 1, y - 1))],
125
+ ['TR', cornerFill(color, east, north, colorAt(x + 1, y - 1))],
126
+ ['BL', cornerFill(color, west, south, colorAt(x - 1, y + 1))],
127
+ ['BR', cornerFill(color, east, south, colorAt(x + 1, y + 1))],
128
+ ];
129
+
130
+ if (color) {
131
+ ctx.fillStyle = rgbaFillStyle(color);
132
+ ctx.fillRect(x, y, 1, 1);
133
+ }
134
+
135
+ if (cornerRadius <= 0) return;
136
+ for (const [corner, reveal] of cuts) {
137
+ if (reveal === NO_CUT) continue;
138
+ ctx.beginPath();
139
+ tracePixelWedge(ctx, corner, x, y, cornerRadius);
140
+ if (reveal === null) {
141
+ // Revealing transparency: clip to the wedge and clear it, rather than
142
+ // fill it, since there's no color to paint.
143
+ ctx.save();
144
+ ctx.clip();
145
+ ctx.clearRect(x, y, 1, 1);
146
+ ctx.restore();
147
+ } else {
148
+ ctx.fillStyle = rgbaFillStyle(reveal);
149
+ ctx.fill();
150
+ }
151
+ }
152
+ }
153
+
154
+ // Classify one corner of pixel `color`, given its two edge-adjacent
155
+ // neighbors (`a`, `b`) and its diagonal neighbor (`g`). Returns the neighbor
156
+ // color to reveal at that corner's rounded cut, or `NO_CUT` to leave the
157
+ // corner sharp:
158
+ // - `a` or `b` matches `color`: either a flat/interior corner, or (when
159
+ // they don't BOTH match) a straight edge passing by rather than a real
160
+ // corner. Either way, nothing to round from P's side — a matching
161
+ // neighbor's OWN corner classification (evaluated independently, when
162
+ // IT is P) is what rounds the opposite case; the physical wedge that
163
+ // gets cut always lives entirely inside whichever pixel's corner is
164
+ // convex, so there's no double-handling.
165
+ // - neither `a` nor `b` matches, but `g` DOES: a diagonal touch between
166
+ // two same-colored pixels (the "checkerboard" case). Left uncut, so a
167
+ // smoothed diagonal stroke doesn't get visually pinched off at every
168
+ // step.
169
+ // - neither `a`, `b`, nor `g` matches, and `a` and `b` are THE SAME color:
170
+ // a genuine, unambiguous convex corner of P's own region touching one
171
+ // other region. Cut it, revealing that color.
172
+ // - neither `a`, `b`, nor `g` matches, and `a` and `b` DIFFER: three (or
173
+ // four, counting `g`) distinct colors meet at this exact point — e.g. a
174
+ // "T" where one region's straight edge is crossed by the boundary
175
+ // between two others. Left uncut. Rounding here would have to guess
176
+ // which of `a`/`b` "wins", and since the pixel on the OTHER side of
177
+ // that guess is classifying this same point independently — and would
178
+ // guess differently — a pair of pixels each revealing the OTHER's
179
+ // color produces a little criss-crossed notch instead of one clean
180
+ // curve. Leaving every pixel at a 3+-way point sharp keeps it a single
181
+ // consistent (if unrounded) vertex.
182
+ function cornerFill(color, a, b, g) {
183
+ if (a === color || b === color) return NO_CUT;
184
+ if (g === color) return NO_CUT;
185
+ return a === b ? a : NO_CUT;
186
+ }
187
+
188
+ // `color` is always a `"r,g,b,a"` string (0-255 channels, alpha 0-255) —
189
+ // see `colorAt` — never the transparent sentinel (only opaque colors ever
190
+ // reach this function as `color`, only ever as `reveal`).
191
+ function rgbaFillStyle(color) {
192
+ const [r, g, b, a] = color.split(',').map(Number);
193
+ return `rgba(${r}, ${g}, ${b}, ${a / 255})`;
194
+ }
195
+
196
+ // Trace the small corner wedge that gets cut from pixel (x, y)'s unit square
197
+ // at `corner` (one of 'TL' | 'TR' | 'BL' | 'BR'): the sliver between the
198
+ // exact corner point and the quarter-circle of radius `r` tangent to both
199
+ // adjacent edges at distance `r` from the corner — i.e. exactly the piece a
200
+ // standard rounded-rect corner removes from a sharp one. `ctx.arcTo`'s
201
+ // corner-point-as-control-point form draws that same tangent arc without
202
+ // hand-computed sweep angles.
203
+ function tracePixelWedge(ctx, corner, x, y, r) {
204
+ if (corner === 'TL') {
205
+ ctx.moveTo(x, y);
206
+ ctx.lineTo(x + r, y);
207
+ ctx.arcTo(x, y, x, y + r, r);
208
+ } else if (corner === 'TR') {
209
+ ctx.moveTo(x + 1, y);
210
+ ctx.lineTo(x + 1, y + r);
211
+ ctx.arcTo(x + 1, y, x + 1 - r, y, r);
212
+ } else if (corner === 'BL') {
213
+ ctx.moveTo(x, y + 1);
214
+ ctx.lineTo(x, y + 1 - r);
215
+ ctx.arcTo(x, y + 1, x + r, y + 1, r);
216
+ } else {
217
+ ctx.moveTo(x + 1, y + 1);
218
+ ctx.lineTo(x + 1 - r, y + 1);
219
+ ctx.arcTo(x + 1, y + 1, x + 1, y + 1 - r, r);
220
+ }
221
+ ctx.closePath();
222
+ }