Draw the wind-up from the photographed serve, not from prose
Oliver's idea, and it is the fix for the process as much as for the frames: give the generator the real serve sequence as an IMAGE and let it copy the poses, instead of describing a pose in prose and re-rolling until it lands. One generation — a composite of his five photographed frames over two of our sprites — returned a magenta row of the whole serve in the game's own character and kit. The four stages are sliced straight out of it, anchored on the standing figure. _fine.py gets --defringe: its two de-fringe passes each eat a one-pixel line, and a racket frame IS a one-pixel line — that is what had been leaving the men holding a grip and nothing else. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
No files matched your search
@@ -17,7 +17,7 @@ KEY_D2 = 60 * 60
|
||||
MIN_GAP = 12
|
||||
MIN_BLOB = 60
|
||||
|
||||
def key(im):
|
||||
def key(im, defringe=2):
|
||||
a = np.array(im.convert('RGBA'))
|
||||
bg = a[0, 0, :3].astype(int)
|
||||
d = ((a[..., :3].astype(int) - bg) ** 2).sum(2)
|
||||
@@ -26,7 +26,10 @@ def key(im):
|
||||
# De-fringe. The generator does not always give you a pure key colour, and whatever it does give
|
||||
# bleeds a halo one pixel into the sprite — which survives as a magenta rim once the sprite is on
|
||||
# a green court. Anything on the EDGE that is still leaning towards the background goes too.
|
||||
for _ in range(2):
|
||||
# ...but each pass also eats a 1-pixel line, and a racket frame IS a 1-pixel line: two passes
|
||||
# removed the rackets from a whole serve sheet and left men holding a grip. --defringe 1 (or 0)
|
||||
# is for sheets whose art is that thin.
|
||||
for _ in range(defringe):
|
||||
solid = a[..., 3] > 0
|
||||
edge = solid & ~(np.roll(solid, 1, 0) & np.roll(solid, -1, 0) & np.roll(solid, 1, 1) & np.roll(solid, -1, 1))
|
||||
near = ((a[..., :3].astype(int) - bg) ** 2).sum(2) < KEY_D2 * 9
|
||||
@@ -67,8 +70,8 @@ def frames(a, cuts):
|
||||
if x0 < c < x1: out[i:i+1] = [(x0, c), (c, x1)]; break
|
||||
return out
|
||||
|
||||
def main(sheet, outs, target_h, cuts, anchor):
|
||||
a = key(Image.open(sheet))
|
||||
def main(sheet, outs, target_h, cuts, anchor, defringe=2):
|
||||
a = key(Image.open(sheet), defringe)
|
||||
b = block_size(a)
|
||||
crops = []
|
||||
for x0, x1 in frames(a, cuts):
|
||||
@@ -104,5 +107,7 @@ if __name__ == '__main__':
|
||||
th, cuts, anchor = TARGET_H, [], -1
|
||||
if '--h' in args: i = args.index('--h'); th = int(args[i+1]); del args[i:i+2]
|
||||
if '--cut' in args: i = args.index('--cut'); cuts = [int(v) for v in args[i+1].split(',')]; del args[i:i+2]
|
||||
de = 2
|
||||
if '--defringe' in args: i = args.index('--defringe'); de = int(args[i+1]); del args[i:i+2]
|
||||
if '--anchor' in args: i = args.index('--anchor'); anchor = int(args[i+1]); del args[i:i+2]
|
||||
main(args[0], args[1:], th, cuts, anchor)
|
||||
main(args[0], args[1:], th, cuts, anchor, de)
|
||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 11 KiB |
@@ -97,6 +97,6 @@
|
||||
<p id="build"></p>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="main.js?v=78"></script>
|
||||
<script type="module" src="main.js?v=79"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -155,7 +155,7 @@ export function proj(x, y, z) {
|
||||
|
||||
// ---------------------------------------------------------------- sprites ----
|
||||
// assets/<name>.png; game falls back to code-drawn figures until sprites load.
|
||||
const SPRV = 71; // asset cache-buster — bump with main.js?v=N (see the img.src note below)
|
||||
const SPRV = 72; // asset cache-buster — bump with main.js?v=N (see the img.src note below)
|
||||
const SPR = {};
|
||||
for (const n of ['p_idle1','p_idle2','p_bounce','p_bounce2','p_toss','p_smash','p_run1','p_run2','p_run3','p_run4','p_swing1','p_swing2','p_die1','p_die2','p_die3','p_die4','p_die5',
|
||||
'p_pull1','p_pull2','p_pull3','p_pull4', // the serve WIND-UP, one frame per quarter of the pull (see drawChar)
|
||||
|
||||