ONE palette gate replaces four feature-picked ones

Oliver, on the brute's fall frames: "now the fall zombie has a different skin
tone.. man this is all so tiresome." Both halves were right. The skin IS twenty
points lighter across that sheet, and the tiresome part is mine: I had been
adding one hand-picked gate per drift I discovered — redness, then hue, then
`changed`, then no-grids — which is a loop with no end, because naming features
is not the same as comparing pictures.

`kit` names four: shirt redness, shorts brightness, shorts hue, near-white
fraction. Every character breaks a different one. The brute's shirt has no red
in it at all, so its reference redness was 0 and blood scored 70-100 against a
tolerance meant for a garment. A body face down shows a fraction of the shirt it
shows standing, so two of the four move with POSE. And nothing in that list ever
measured SKIN, which is exactly how a brute's flesh drifted across a whole sheet
with six gates green.

The palette gate asks the only question that generalises: are the big colour
areas of this frame the same colours as the anchor's? Top SIX by area — the
garments and the skin. Proportions ignored, so a pose change is invisible; blood
is never in the top six, so a fresh wound cannot look like drift.

CALIBRATED BEFORE IT WAS WIRED IN, which is the discipline I skipped all day.
Frames known to be right score 0.0-8.5; the drifts we could actually see score
12.0-15.9. The threshold is 10, in the gap. Three formulations were measured and
the two that overlapped were thrown away.

And every sheet of a variant is now anchored to that variant's FIRST sheet, not
to the stage above it. Chaining let a legal hop compound into a drift nobody
authorised — the shorts walking -9 to -19 down the wound ladder was that, and so
was this.

Its first verdict on the existing brute: br_play is the character, and every
other sheet sits 15 to 48 away from it. It would have caught all of this on the
first roll.

Also in: the GRID guard from the same session — the valley-cut rescue would slice
a 2x2 sheet into four frames of a torso above someone else's boots, turning a
loud failure into a silent one. Asked per cut PIECE, because a body is vertically
continuous and a piece with a gap in it caught two of them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-08-12 13:45:41 +02:00
1 parent df454c5d92
commit 0e92c72457
33 files changed
+312 -19

No files matched your search

Binary file not shown.
+34 -1
View File
@@ -92,6 +92,34 @@ def valley_cuts(ink_cols, x0, x1, n):
out.append(lo + int(np.argmin(ink_cols[lo:hi])))
return out
# DO THE FIGURES SHARE A GROUND LINE? That is the invariant every prompt in this project asks for,
# and it is the one that tells a ROW from a GRID. An empty-band test does not: in the sheet that
# caught this, a 2x2 of a brute falling, the bottom-right figure was tall enough to overlap the top
# row and there was no clean horizontal gap anywhere.
#
# It matters because the valley rescue below will cut ANY sheet into the number of columns it was
# asked for — and on a grid each column is a torso above someone else's boots. Four such frames
# installed silently and looked, in the log, exactly like a success. The rescue turned a loud failure
# into a quiet one, which is the worst trade available in this file; this is the check that stops it.
# IS THIS ONE FIGURE, OR TWO STACKED? Asked of each CUT PIECE, not of the sheet. A body is
# vertically continuous — head to feet there is no height at which the piece is empty — so a
# full-width empty band inside a piece's own extent means the cut caught someone's torso above
# someone else's boots.
#
# Asking it of the whole sheet does not work, and both weaker versions were tried: an empty-band test
# on the sheet fails when a grid's bottom-right figure is tall enough to overlap the top row, and a
# shared-ground-line test fails because after a bad cut EVERY column reaches the bottom row's feet.
# The piece is the only place the question has a clean answer.
def split_piece(crop):
rows = (crop[..., 3] > 0).any(1)
ys = np.where(rows)[0]
if not len(ys): return False
run = best = 0
for y in range(ys.min(), ys.max() + 1):
run = 0 if rows[y] else run + 1
if run > best: best = run
return best >= MIN_GAP * 2
def frames(a, cuts, want=0):
ink = (a[..., 3] > 0)
cols = ink.any(0)
@@ -122,12 +150,17 @@ 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, len(outs)):
spans = frames(a, cuts, len(outs))
for x0, x1 in spans:
sub = a[:, x0:x1]
ys = np.where((sub[..., 3] > 0).any(1))[0]; xs = np.where((sub[..., 3] > 0).any(0))[0]
crops.append(sub[ys.min():ys.max()+1, xs.min():xs.max()+1])
if len(crops) != len(outs):
sys.exit(f'ERROR: found {len(crops)} frames, expected {len(outs)} ({sheet})')
bad = [i for i, c in enumerate(crops) if split_piece(c)]
if bad:
sys.exit(f'ERROR: frame(s) {bad} contain two stacked bodies — the sheet is a GRID, not one '
f'row ({sheet})')
# palette = the colours the generator actually used, on the largest frame
big = max(crops, key=lambda c: (c[..., 3] > 0).sum())
px = big[big[..., 3] > 200][:, :3]
+13 -9
View File
@@ -107,18 +107,22 @@ def variant(key, who):
made = []
def batch(name, sprites, refs, subject, stride=None, changed=None, newart=False):
for src, dst in zip(refs, sprites): # placeholders: the density bar needs a baseline to beat
seed(src, dst)
# Only the sheets drawn off the MASTER are seeded here. A chained wound stage is seeded by
# _regen at run time, from whatever its reference has become by then — seeding it now would
# score it against a copy of the master, two steps better than the stage it follows.
if newart:
for src, dst in zip(refs, sprites):
seed(src, dst)
spec = dict(sprites=sprites, ref_only=list(refs), check='loose', anchor=0, subject=subject)
spec['newart' if newart else 'state'] = True
if stride: spec['stride'] = stride
if changed:
spec['changed'] = changed
# pose-varied sheets move redness and shorts BRIGHTNESS on their own (a body face down
# shows a fraction of the shirt it shows standing); the shorts HUE is the measure that
# survives a pose change, so it stays the tight one. See the note in _regen.kit.
spec['palette_ref'] = refs[0]
spec['palette_tol'] = [26, 14, 99, 5]
if changed: spec['changed'] = changed
# EVERY SHEET OF A VARIANT IS PAINTED IN THE FIRST SHEET'S COLOURS. Anchoring each stage to
# the one before it let a legal hop compound into a drift nobody authorised; anchoring all of
# them to the healthy body means the whole variant, wounds and all, stays one character.
# The first sheet is what DEFINES the palette, so it is the only one not measured against it.
if sprites[0] != K + '1':
spec['palette_anchor'] = K + '1'
B[name] = spec
made.append(name)
print(f'{name:16s} <- {refs[0]}… {", ".join(sprites)}')
+81 -9
View File
@@ -12,7 +12,7 @@
# real gain in inner-edge density (the number that tracks "is the drawing actually finer").
#
# Failures leave the sprites alone and print why, so a batch can just be re-run.
import json, os, subprocess, sys
import json, os, shutil, subprocess, sys
import numpy as np
from PIL import Image
@@ -147,6 +147,13 @@ def kit(path):
# NOTE the fourth tolerance: kit() returns four numbers and kit_off zips them against this, so a
# three-long tuple would silently skip the hue check rather than fail — the same shape of no-op the
# read-only floodfill in _fine.py was. Every caller passing its own `palette_tol` needs four too.
# A measure only means something if the garment it measures EXISTS. The brute wears a pale grey-green
# work shirt with no red in it at all, so the reference's redness is 0 and every roll with a spot of
# blood on it scored 70-100 — twenty-six points of tolerance against a number that was never
# measuring a shirt. Below this floor `redness` is reading BLOOD, which is supposed to change between
# wound stages, so the axis is skipped rather than fought. The tolerances in a batch were calibrated
# on a red-shirted zombie; a variant inherits them and must not inherit their assumptions.
RED_FLOOR = 40
def kit_off(outs, ref_name, tol=(12, 10, 1.5, 4)):
"""Is this roll wearing the right kit? Generative rolls drift the palette EVERY TIME and nothing
else here catches it: colour_match only runs for `check: finer`, and it is a global mean/sd fit
@@ -154,9 +161,10 @@ def kit_off(outs, ref_name, tol=(12, 10, 1.5, 4)):
headband, the toss shipped twice in pale grey shorts, and a swing pair shipped in brown shoes.
Compared against a canonical frame that is NOT part of the batch (o_idle1 for the opponent)."""
ref = kit(os.path.join(HERE, ref_name + '.png'))
skip = [ref[0] < RED_FLOOR, False, False, False] # no red garment -> redness means nothing
for o in outs:
got = kit(o)
if any(abs(g - r) > t for g, r, t in zip(got, ref, tol)):
if any(abs(g - r) > t for i, (g, r, t) in enumerate(zip(got, ref, tol)) if not skip[i]):
return (f'kit drifted vs {ref_name}: redness/shorts/bright {got} vs {ref} '
f'(tolerance {tol})')
return None
@@ -208,11 +216,18 @@ def changed_off(outs, refs, want):
for o, r in zip(outs, refs):
rp = os.path.join(HERE, r + '.png')
if not os.path.exists(rp): continue
_, _, ma, mb, _ = _masks(o, rp)
d = _d(ma, mb)
if d < want:
_, _, ma, mb, h = _masks(o, rp)
# WHOLE BODY *OR* UPPER BODY, whichever moved more. An arm is a body-relative amount of
# silhouette: on the lean club pro it is 12-38% of him, on a brute twice his width it is 9%,
# so a threshold calibrated on one rejects a perfectly good amputation on the other. Above
# the hip is where an arm lives, and there the same removal reads roughly twice as loud —
# the stride gate splits at the same line for the same reason.
hip = int(h * STRIDE_HIP)
d, up = _d(ma, mb), _d(ma[:hip], mb[:hip])
if max(d, up) < want:
return (f'{os.path.basename(o)} is {r} redrawn — only {d:.3f} of the silhouette differs '
f'(want >= {want}). The thing that was supposed to change did not change.')
f'({up:.3f} above the hip, want >= {want}). '
f'The thing that was supposed to change did not change.')
return None
def stride_off(outs, pairs):
@@ -227,6 +242,41 @@ def stride_off(outs, pairs):
f'want ~1.00 / <={STRIDE_TOP} / >={STRIDE_LEG})')
return None
# ---- THE PALETTE GATE, which replaces four hand-picked ones. `kit` names features — shirt redness,
# shorts brightness, shorts hue, near-white fraction — and every character breaks a different one:
# the brute's shirt has no red in it, a body face down shows a fraction of the shirt it shows
# standing, and NOTHING in that list ever measured SKIN, which is how a brute's flesh got twenty
# points lighter across its fall sheet without a single gate noticing.
#
# This asks the only question that generalises: are the big colour areas of this frame the same
# colours as the anchor's? Top SIX by area — the garments and the skin. Proportions are ignored, so a
# pose change is invisible; blood is never in the top six, so a fresh wound cannot look like drift.
# Calibrated on frames known to be right (0.0-8.5) against the drifts we could see (12.0-15.9), so
# the default sits in the gap. One number, no per-character tuning.
def dom_colours(path, n=6, q=8, floor=0.005):
a = np.array(Image.open(path).convert('RGBA')).astype(int)
px = a[..., :3][a[..., 3] > 128]
if not len(px): return np.zeros((0, 3)), np.zeros(0)
u, c = np.unique((px // q) * q, axis=0, return_counts=True)
k = c / c.sum() >= floor
u, c = u[k], c[k] / c[k].sum()
o = np.argsort(-c)[:n]
return u[o], c[o] / c[o].sum()
def palette_off(outs, anchor, want):
ap = os.path.join(HERE, anchor + '.png')
if not os.path.exists(ap): return None
ua, _ = dom_colours(ap)
if not len(ua): return None
for o in outs:
uo, wo = dom_colours(o)
if not len(uo): continue
d = float((np.sqrt(((uo[:, None, :] - ua[None, :, :]) ** 2).sum(2)).min(1) * wo).sum())
if d > want:
return (f'{os.path.basename(o)} is not painted in {anchor}\'s colours — its main areas sit '
f'{d:.1f} away (want <= {want}). Something the size of a garment or the skin changed.')
return None
def not_magenta(sheet):
"""The generator sometimes ignores the magenta and paints its own background. That was written
off as harmless — the key uses the corner colour — right up until it returned a GREEN sheet and
@@ -300,6 +350,15 @@ def run(name, spec, dry=False):
if r.returncode or not all(os.path.exists(o) for o in outs):
print(f'[{name}] REJECTED: slicing failed (frames merged?) — re-run or add "cut"'); return False
if lead: outs = outs[1:] # the scale reference is not installed
# A CHAINED BATCH'S BASELINE IS ITS REFERENCE, MEASURED NOW. Seeding every placeholder up front
# meant a wound stage was scored against a copy of the MASTER — art two steps better than the
# stage it actually follows — and three brute batches were rejected for not out-detailing a
# sheet they were never drawn from.
refs0 = spec.get('ref_only') or []
if len(refs0) == len(sprites):
for r, t in zip(refs0, sprites):
tp, rp = (os.path.join(HERE, n + '.png') for n in (t, r))
if not os.path.exists(tp) and os.path.exists(rp): shutil.copy(rp, tp)
before = [density(os.path.join(HERE, s + '.png')) for s in sprites]
after = [density(o) for o in outs]
# Two jobs, two bars. A coarse->fine REDRAW has to be measurably finer (1.25x, not 1.5x: a sheet
@@ -315,7 +374,11 @@ def run(name, spec, dry=False):
bar = {'finer': 1.25, 'same': 0.85, 'loose': 0.7, 'any': 0.0}[spec.get('check', 'finer')]
if sum(after) / len(after) < sum(before) / len(before) * bar:
print(f'[{name}] REJECTED: not finer than what it replaces {before} -> {after}'); return False
if spec.get('palette_ref'):
# the palette gate supersedes the feature-picked kit gate wherever a batch declares an anchor
if spec.get('palette_anchor'):
bad = palette_off(outs, spec['palette_anchor'], spec.get('palette_max', 10))
if bad: print(f'[{name}] REJECTED: {bad}'); return False
elif spec.get('palette_ref'):
bad = kit_off(outs, spec['palette_ref'], tuple(spec.get('palette_tol', (12, 10, 1.5))))
if bad: print(f'[{name}] REJECTED: {bad}'); return False
if spec.get('stride'):
@@ -363,11 +426,20 @@ if __name__ == '__main__':
for a in args: # frames merged, or a limb off the canvas
if a.startswith('--tries='): tries = int(a.split('=')[1])
names = list(B) if '--all' in args else [a for a in args if not a.startswith('--')]
bad = []
bad, stale = [], set()
for n in names:
# A CHAINED BATCH IS DRAWN FROM THE STAGE ABOVE IT, so if that stage failed its reference is
# still a placeholder and whatever comes back is drawn from the wrong body. The brute's
# headless sheet installed cleanly off an arm-off stage that never landed — three perfect
# frames of a two-armed corpse. Skipping is the only honest answer; running is worse than
# failing, because it SUCCEEDS.
blocked = [r for r in (B[n].get('ref_only') or []) if r in stale]
if blocked:
print(f'[{n}] SKIPPED: drawn from {", ".join(blocked)}, which did not land')
bad.append(n); stale.update(B[n]['sprites']); continue
for attempt in range(1, tries + 1):
if run(n, B[n], dry): break
print(f'[{n}] attempt {attempt}/{tries} rejected')
else:
bad.append(n)
bad.append(n); stale.update(B[n]['sprites'])
print('\nFAILED BATCHES (re-run):', ' '.join(bad) if bad else 'none')
+184
View File
@@ -1433,5 +1433,189 @@
],
"subject": "The reference image is a SPRITE SHEET of ONE zombie tennis player, 4 frames. REDRAW THE WHOLE SHEET with ONE THING CHANGED: his HEAD IS COMPLETELY GONE — no head, no face, no hair, no headband anywhere above the shoulders, only a ragged gushing neck stump, so every figure is A CLEAR HEAD SHORTER than in the reference. He is ALREADY missing his left arm in the reference and it STAYS gone — he still has only one arm. EVERYTHING ELSE STAYS EXACTLY AS IT IS IN THE REFERENCE — the same character, the same red shirt, the same WARM CHARCOAL shorts and their exact shade, the same grey-green skin, the same white socks and shoes, the same wooden racket, the same 4 poses in the same order, the same body positions, the same facing, the same heights. Output exactly 4 figures side by side in ONE horizontal row. THERE IS NO TENNIS BALL ANYWHERE IN ANY FRAME. Do not draw a ball in his hand, in the air, on the ground or on the racket — the ball is drawn separately by the game. His hands and the air around him are EMPTY, and the poses are the same as if a ball were there. ",
"changed": 0.15
},
"br_play": {
"sprites": [
"z_br1",
"z_br2",
"z_br3",
"z_br4"
],
"ref_only": [
"z_r1",
"z_r2",
"z_r3",
"z_r4"
],
"check": "loose",
"anchor": 0,
"subject": "The reference image is a 4-FRAME SPRITE SHEET of one zombie tennis player. Redraw THE WHOLE SHEET as a COMPLETELY DIFFERENT ZOMBIE: an ENORMOUS FAT ZOMBIE BRUTE — the same creature as this game's brute, now playing tennis: a HUGE SAGGING BELLY hanging out over the belt, a filthy PALE GREY-GREEN button-up work shirt straining over it, dark stains and a torn ragged hem, heavy OLIVE-BROWN work trousers, thick tree-trunk legs, scuffed brown boots, a SMALL BALD HEAD sunk low into massive rounded shoulders, heavy jowls, sunken eyes, green-grey dead skin, and a wooden tennis racket looking tiny in one huge fist. He is FAR bulkier, heavier and wider than the lean man in the reference — twice his width — and much shorter in the neck. KEEP ALL 4 POSES EXACTLY AS THEY ARE IN THE REFERENCE — the same stance, the same steps with the same leg forward in each, the same swing, the same facing, the same arm and racket positions, the same order left to right, the same total height and the same distance from the camera. Only the CHARACTER changes; the POSES do not. There is NO TENNIS BALL anywhere in any frame — the game draws the ball itself, so the hands and the air are empty and the poses are the same as if a ball were there. Output exactly 4 figures side by side in ONE horizontal row, all on the same ground line. In particular frames 2 and 3 must stay what they are in the reference: ONE DRAWING SHOWN TWICE with only the legs different — everything above the hips identical between them, the legs clearly swapped, and the two frames NOT identical copies. ",
"newart": true,
"stride": [
[
1,
2
]
]
},
"br_serve": {
"sprites": [
"z_brbounce",
"z_brtoss",
"z_brserve"
],
"ref_only": [
"z_rbounce",
"z_rtoss",
"z_rserve"
],
"check": "loose",
"anchor": 0,
"subject": "The reference image is a 3-FRAME SPRITE SHEET of one zombie tennis player. Redraw THE WHOLE SHEET as a COMPLETELY DIFFERENT ZOMBIE: an ENORMOUS FAT ZOMBIE BRUTE — the same creature as this game's brute, now playing tennis: a HUGE SAGGING BELLY hanging out over the belt, a filthy PALE GREY-GREEN button-up work shirt straining over it, dark stains and a torn ragged hem, heavy OLIVE-BROWN work trousers, thick tree-trunk legs, scuffed brown boots, a SMALL BALD HEAD sunk low into massive rounded shoulders, heavy jowls, sunken eyes, green-grey dead skin, and a wooden tennis racket looking tiny in one huge fist. He is FAR bulkier, heavier and wider than the lean man in the reference — twice his width — and much shorter in the neck. KEEP ALL 3 POSES EXACTLY AS THEY ARE IN THE REFERENCE — the same stance, the same steps with the same leg forward in each, the same swing, the same facing, the same arm and racket positions, the same order left to right, the same total height and the same distance from the camera. Only the CHARACTER changes; the POSES do not. There is NO TENNIS BALL anywhere in any frame — the game draws the ball itself, so the hands and the air are empty and the poses are the same as if a ball were there. Output exactly 3 figures side by side in ONE horizontal row, all on the same ground line. ",
"newart": true,
"palette_anchor": "z_br1"
},
"br_fall": {
"sprites": [
"z_brfall1",
"z_brfall2",
"z_brfall3",
"z_brrise"
],
"ref_only": [
"z_rfall1",
"z_rfall2",
"z_rfall3",
"z_rrise"
],
"check": "loose",
"anchor": 0,
"subject": "The reference image is a 4-FRAME SPRITE SHEET of one zombie tennis player. Redraw THE WHOLE SHEET as a COMPLETELY DIFFERENT ZOMBIE: an ENORMOUS FAT ZOMBIE BRUTE — the same creature as this game's brute, now playing tennis: a HUGE SAGGING BELLY hanging out over the belt, a filthy PALE GREY-GREEN button-up work shirt straining over it, dark stains and a torn ragged hem, heavy OLIVE-BROWN work trousers, thick tree-trunk legs, scuffed brown boots, a SMALL BALD HEAD sunk low into massive rounded shoulders, heavy jowls, sunken eyes, green-grey dead skin, and a wooden tennis racket looking tiny in one huge fist. He is FAR bulkier, heavier and wider than the lean man in the reference — twice his width — and much shorter in the neck. KEEP ALL 4 POSES EXACTLY AS THEY ARE IN THE REFERENCE — the same stance, the same steps with the same leg forward in each, the same swing, the same facing, the same arm and racket positions, the same order left to right, the same total height and the same distance from the camera. Only the CHARACTER changes; the POSES do not. There is NO TENNIS BALL anywhere in any frame — the game draws the ball itself, so the hands and the air are empty and the poses are the same as if a ball were there. Output exactly 4 figures side by side in ONE horizontal row, all on the same ground line. ",
"newart": true,
"palette_anchor": "z_br1"
},
"br_w1": {
"sprites": [
"z_brw1",
"z_brw1b",
"z_brw1s"
],
"ref_only": [
"z_br2",
"z_br3",
"z_br4"
],
"check": "loose",
"anchor": 0,
"subject": "The reference image is a 3-FRAME SPRITE SHEET of one zombie tennis player. REDRAW THE WHOLE SHEET with ONE THING CHANGED: the arm WITHOUT the racket is COMPLETELY GONE — torn off at the shoulder, leaving a ragged stump gushing blood down that side and the clothing slashed open across the ribs. COUNT THE ARMS: there must be EXACTLY ONE ARM in every single frame, the one holding the racket. Nothing hangs from the other shoulder. A frame with two arms in it is wrong — this is the whole change being asked for, so do not copy the reference's second arm across. Where the reference uses that arm, the stump is thrown out in its place instead. EVERYTHING ELSE STAYS EXACTLY AS IT IS IN THE REFERENCE — the same character, the same clothing and its exact shades, the same skin, the same racket, the same 3 poses in the same order, the same leg positions, the same facing, the same build. There is NO TENNIS BALL in any frame. Output exactly 3 figures side by side in ONE horizontal row, all on the same ground line. In particular frames 1 and 2 are ONE DRAWING SHOWN TWICE with only the legs different — identical above the hips, legs clearly swapped, and NOT identical copies. ",
"state": true,
"stride": [
[
0,
1
]
],
"changed": 0.1,
"palette_anchor": "z_br1"
},
"br_serve_w1": {
"sprites": [
"z_brw1bounce",
"z_brw1toss",
"z_brw1serve"
],
"ref_only": [
"z_brbounce",
"z_brtoss",
"z_brserve"
],
"check": "loose",
"anchor": 0,
"subject": "The reference image is a 3-FRAME SPRITE SHEET of one zombie tennis player. REDRAW THE WHOLE SHEET with ONE THING CHANGED: the arm WITHOUT the racket is COMPLETELY GONE — torn off at the shoulder, leaving a ragged stump gushing blood down that side and the clothing slashed open across the ribs. COUNT THE ARMS: there must be EXACTLY ONE ARM in every single frame, the one holding the racket. Nothing hangs from the other shoulder. A frame with two arms in it is wrong — this is the whole change being asked for, so do not copy the reference's second arm across. Where the reference uses that arm, the stump is thrown out in its place instead. EVERYTHING ELSE STAYS EXACTLY AS IT IS IN THE REFERENCE — the same character, the same clothing and its exact shades, the same skin, the same racket, the same 3 poses in the same order, the same leg positions, the same facing, the same build. There is NO TENNIS BALL in any frame. Output exactly 3 figures side by side in ONE horizontal row, all on the same ground line. Because it has only one arm it can no longer throw the ball up with a free hand: in the TOSS frame the stump is flung upward instead and the racket hand flicks up in front of the face, as a one-armed player tosses off the racket face. ",
"state": true,
"changed": 0.1,
"palette_anchor": "z_br1"
},
"br_fall_w1": {
"sprites": [
"z_brw1fall1",
"z_brw1fall2",
"z_brw1fall3",
"z_brw1rise"
],
"ref_only": [
"z_brfall1",
"z_brfall2",
"z_brfall3",
"z_brrise"
],
"check": "loose",
"anchor": 0,
"subject": "The reference image is a 4-FRAME SPRITE SHEET of one zombie tennis player. REDRAW THE WHOLE SHEET with ONE THING CHANGED: the arm WITHOUT the racket is COMPLETELY GONE — torn off at the shoulder, leaving a ragged stump gushing blood down that side and the clothing slashed open across the ribs. COUNT THE ARMS: there must be EXACTLY ONE ARM in every single frame, the one holding the racket. Nothing hangs from the other shoulder. A frame with two arms in it is wrong — this is the whole change being asked for, so do not copy the reference's second arm across. Where the reference uses that arm, the stump is thrown out in its place instead. EVERYTHING ELSE STAYS EXACTLY AS IT IS IN THE REFERENCE — the same character, the same clothing and its exact shades, the same skin, the same racket, the same 4 poses in the same order, the same leg positions, the same facing, the same build. There is NO TENNIS BALL in any frame. Output exactly 4 figures side by side in ONE horizontal row, all on the same ground line. ",
"state": true,
"changed": 0.1,
"palette_anchor": "z_br1"
},
"br_w2": {
"sprites": [
"z_brw2",
"z_brw2b",
"z_brw2s"
],
"ref_only": [
"z_brw1",
"z_brw1b",
"z_brw1s"
],
"check": "loose",
"anchor": 0,
"subject": "The reference image is a 3-FRAME SPRITE SHEET of one zombie tennis player. REDRAW THE WHOLE SHEET with ONE THING CHANGED: the HEAD IS COMPLETELY GONE — no head, no face, no hair anywhere above the shoulders, only a ragged gushing neck stump, so every figure is A CLEAR HEAD SHORTER than in the reference. It is ALREADY missing one arm in the reference and it STAYS missing — it still has only one arm. EVERYTHING ELSE STAYS EXACTLY AS IT IS IN THE REFERENCE — the same character, the same clothing and its exact shades, the same skin, the same racket, the same 3 poses in the same order, the same leg positions, the same facing, the same build. There is NO TENNIS BALL in any frame. Output exactly 3 figures side by side in ONE horizontal row, all on the same ground line. In particular frames 1 and 2 are ONE DRAWING SHOWN TWICE with only the legs different — identical above the hips, legs clearly swapped, and NOT identical copies. ",
"state": true,
"stride": [
[
0,
1
]
],
"changed": 0.15,
"palette_anchor": "z_br1"
},
"br_serve_w2": {
"sprites": [
"z_brw2bounce",
"z_brw2toss",
"z_brw2serve"
],
"ref_only": [
"z_brw1bounce",
"z_brw1toss",
"z_brw1serve"
],
"check": "loose",
"anchor": 0,
"subject": "The reference image is a 3-FRAME SPRITE SHEET of one zombie tennis player. REDRAW THE WHOLE SHEET with ONE THING CHANGED: the HEAD IS COMPLETELY GONE — no head, no face, no hair anywhere above the shoulders, only a ragged gushing neck stump, so every figure is A CLEAR HEAD SHORTER than in the reference. It is ALREADY missing one arm in the reference and it STAYS missing — it still has only one arm. EVERYTHING ELSE STAYS EXACTLY AS IT IS IN THE REFERENCE — the same character, the same clothing and its exact shades, the same skin, the same racket, the same 3 poses in the same order, the same leg positions, the same facing, the same build. There is NO TENNIS BALL in any frame. Output exactly 3 figures side by side in ONE horizontal row, all on the same ground line. ",
"state": true,
"changed": 0.15,
"palette_anchor": "z_br1"
},
"br_fall_w2": {
"sprites": [
"z_brw2fall1",
"z_brw2fall2",
"z_brw2fall3",
"z_brw2rise"
],
"ref_only": [
"z_brw1fall1",
"z_brw1fall2",
"z_brw1fall3",
"z_brw1rise"
],
"check": "loose",
"anchor": 0,
"subject": "The reference image is a 4-FRAME SPRITE SHEET of one zombie tennis player. REDRAW THE WHOLE SHEET with ONE THING CHANGED: the HEAD IS COMPLETELY GONE — no head, no face, no hair anywhere above the shoulders, only a ragged gushing neck stump, so every figure is A CLEAR HEAD SHORTER than in the reference. It is ALREADY missing one arm in the reference and it STAYS missing — it still has only one arm. EVERYTHING ELSE STAYS EXACTLY AS IT IS IN THE REFERENCE — the same character, the same clothing and its exact shades, the same skin, the same racket, the same 4 poses in the same order, the same leg positions, the same facing, the same build. There is NO TENNIS BALL in any frame. Output exactly 4 figures side by side in ONE horizontal row, all on the same ground line. ",
"state": true,
"changed": 0.15,
"palette_anchor": "z_br1"
}
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB