The two dims stopped stacking, and centre court's crowd is graded off a lifted target
Oliver: "it is too dim to see anything on the centre court and the dark court." Both were the same mistake — standBack was ADDED to a court's own dim instead of being the default it falls back to. Centre court's crowd sheet is a night-lit navy that is dark to begin with, and the night court dims the hard-court sheet on top of that, so the pair of them went to mud. standDim is now court.dim ?? TUNE.standBack, plus the rot. Centre court carries a 0.06 of its own, the night court comes down 0.62 -> 0.5 (it no longer has the base added to it), and clay and hard keep the 0.22 that was approved. Centre court's sheet is also graded off a LIFTED target now — the old crowd it matches sat at a mean luminance of 39 against clay's 96, dark enough to throw the new roll's detail away before any dim ran. A 0.72 gamma on the target brings the sheet to 60 and the faces come back. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0250e9bd20
commit
eab0a4e837
5 files changed
+29
-15
No files matched your search
+11
-3
@@ -55,7 +55,12 @@ PAL = 128 # colours a sheet is quantised to on save
|
||||
# HEAD, so re-running the tool after installing its own output cannot drift the palettes.
|
||||
GRADE_REF = '76ea1d0'
|
||||
|
||||
COURTS = [('x_crowd', 'x_crowd2'), ('x_crowd_c', 'x_crowd_c2'), ('x_crowd_h', 'x_crowd_h2')]
|
||||
# sheet -> how much its grade TARGET is lifted before the histogram match (a gamma; 1.0 is the old
|
||||
# sheet as it was). Centre court's old crowd sat at a mean luminance of 39 against clay's 96 — dark
|
||||
# enough that the detail in the new roll was being thrown away, and then dimmed on top of that:
|
||||
# Oliver, "it is too dim to see anything on the centre court and the dark court". The night court
|
||||
# borrows the hard-court sheet and does its own dimming in `COURTS.dim`, so it is fixed there.
|
||||
COURTS = [('x_crowd', 0.72), ('x_crowd_c', 1.0), ('x_crowd_h', 1.0)]
|
||||
|
||||
MIN_AREA, MAX_AREA = 150, 3000 # an arm blob: one pair of raised arms, or one arm
|
||||
ARM_H, ARM_W = (10, 70), (8, 90) # ...and its shape, in px of the 1408x768 sheet
|
||||
@@ -199,8 +204,11 @@ def main(review):
|
||||
print(f'{len(rows)} spectators can move, {both} of them with both poses (a real clap)')
|
||||
|
||||
stack = np.concatenate(frames, 0)
|
||||
for a_name, _ in COURTS:
|
||||
lut = grade(A, old_sheet(a_name)) # the LOOK is judged on the seated frame...
|
||||
for a_name, lift in COURTS:
|
||||
ref = old_sheet(a_name)
|
||||
if lift != 1.0:
|
||||
ref = (255 * (ref / 255.0) ** lift).astype(np.uint8)
|
||||
lut = grade(A, ref) # the LOOK is judged on the seated frame...
|
||||
pa = os.path.join(REFCHECK if review else HERE, a_name + ('_new.png' if review else '.png'))
|
||||
# ...and applied to the whole stack at once, so the frames cannot drift apart in colour
|
||||
Image.fromarray(lut(stack)).quantize(colors=PAL, method=Image.MEDIANCUT).save(pa, optimize=True)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
+1
-1
@@ -661,6 +661,6 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="src/main.js?v=300"></script>
|
||||
<script type="module" src="src/main.js?v=301"></script>
|
||||
</body>
|
||||
</html>
|
||||
+11
-6
@@ -297,10 +297,13 @@ export const TUNE = {
|
||||
// cheered (render's drawClapColumns). Between points the crowd used to be a photograph. This is
|
||||
// deliberately slow and single-column: a stand that fidgets constantly is a stand you look AT.
|
||||
fidgetEvery: 4.5,
|
||||
// HOW FAR BACK THE STAND SITS. A flat dim over the crowd and the boards, on every court, before
|
||||
// the night court's own `dim` and the splatter rot are added on top. Oliver: "all of the art could
|
||||
// be colored a little more dim as it is perspective wise farther in the background and should not
|
||||
// steal too much attention." The crowd is the only thing on screen that is 30 m away.
|
||||
// HOW FAR BACK THE STAND SITS: a flat dim over the crowd and the boards, before the splatter rot
|
||||
// is added on top. Oliver: "all of the art could be colored a little more dim as it is perspective
|
||||
// wise farther in the background and should not steal too much attention." The crowd is the only
|
||||
// thing on screen that is 30 m away.
|
||||
// THIS IS THE DEFAULT, NOT A FLOOR. A court with its own `dim` (centre court's already-dark crowd,
|
||||
// the night court) replaces it rather than adding to it — stacking the two is what made those two
|
||||
// unreadable: "it is too dim to see anything on the centre court and the dark court".
|
||||
standBack: 0.22,
|
||||
// ---- damage. Bodies with hp (racket boss 'r', brute 'g') take damage in these units, so a big
|
||||
// boss is just a bigger hp number and every weapon stays proportional. Fractions are legal: they
|
||||
@@ -694,7 +697,9 @@ export const UI = { hot: '#d9705f', warm: '#e0cc72', pick: '#cbd06a', cream: '#e
|
||||
// sits up and drags, acrylic is the middle it always was.
|
||||
export const COURTS = [
|
||||
{ id: 'grass', name: 'CENTRE COURT', sub: 'GRASS · fast, low skid', tile: 'court_grass',
|
||||
ads: 'x_ads', crowd: 'x_crowd', stripes: true, line: '#e8e8dc', border: '#e8e8dc',
|
||||
// dim 0.06: centre court's crowd is a night-lit navy sheet and is dark to begin with, so it
|
||||
// takes almost none of the standBack default (see TUNE.standBack).
|
||||
ads: 'x_ads', crowd: 'x_crowd', stripes: true, line: '#e8e8dc', border: '#e8e8dc', dim: 0.06,
|
||||
bounceY: 0.50, bounceXZ: 0.84,
|
||||
tennis: { stands: '#232e42', tierA: '#2a3750', tierB: '#26324a', board: '#0e5c2e',
|
||||
out: '#295c2d', lawn: '#4cae52', stripe: '#46a54c' },
|
||||
@@ -726,7 +731,7 @@ export const COURTS = [
|
||||
// court and the whole picture stops being a night. Nothing else in COURTS carries it, so it is 0
|
||||
// everywhere else and reads as absent.
|
||||
{ id: 'gloom', name: 'THE NIGHT COURT', sub: 'AFTER DARK · TRUE BOUNCE, NO LIGHT', tile: 'court_gloom',
|
||||
ads: 'x_ads_h', crowd: 'x_crowd_h', stripes: false, line: '#dff6ff', border: '#c8dbe6', dim: 0.62,
|
||||
ads: 'x_ads_h', crowd: 'x_crowd_h', stripes: false, line: '#dff6ff', border: '#c8dbe6', dim: 0.5,
|
||||
bounceY: 0.58, bounceXZ: 0.80,
|
||||
tennis: { stands: '#0a0d15', tierA: '#0f131e', tierB: '#0c1019', board: '#131a2b',
|
||||
out: '#0f1a15', lawn: '#16261e', stripe: '#16261e' },
|
||||
|
||||
+6
-5
@@ -235,7 +235,7 @@ function farB(z) {
|
||||
// Asset cache-buster — bump with main.js?v=N (see the img.src note below). EXPORTED because the
|
||||
// menu screens hang <img> tags on the same files, and two copies of this number is one copy too
|
||||
// many: the one that does not get bumped is the one that serves a cached 404.
|
||||
export const SPRV = 145;
|
||||
export const SPRV = 146;
|
||||
// The boot bar in main.js watches this. Nothing here CHANGES when things load — every sprite was
|
||||
// already requested at import — it just makes the wait visible and holds the menu back until the
|
||||
// last sheet has landed. See the onerror note below for the other half of "sometimes missing".
|
||||
@@ -420,14 +420,15 @@ function tickFlashes(standsBottom) {
|
||||
ctx.globalAlpha = 1;
|
||||
}
|
||||
|
||||
// How dark the STAND is: `TUNE.standBack` (every court, always — the stand is scenery a long way
|
||||
// behind the court and should not compete with it) plus the court's own night (`dim` on its COURTS
|
||||
// row, 0 everywhere but the night court) plus the rot the splatter palette brings with it. ONE function because it is applied
|
||||
// How dark the STAND is: the court's own `dim` if it names one (centre court's crowd sheet is
|
||||
// already night-dark, the night court is darker still), otherwise `TUNE.standBack` — the stand is
|
||||
// scenery thirty metres back and should not compete with the court — plus the rot the splatter
|
||||
// palette brings with it. ?? not ||: a court that says 0 means 0. ONE function because it is applied
|
||||
// in two places and they must agree exactly — the cached sheet and the live clap columns drawn over
|
||||
// it. Two copies of this number is a stand whose clapping columns pop brighter than the rest of it,
|
||||
// which is the same class of bug as the crowd frames drifting apart. Capped: past ~0.85 the stand
|
||||
// is a black rectangle and the applause stops reading at all.
|
||||
const standDim = pt => Math.min(0.88, TUNE.standBack + (court.dim || 0) + 0.26 * pt);
|
||||
const standDim = pt => Math.min(0.88, (court.dim ?? TUNE.standBack) + 0.26 * pt);
|
||||
|
||||
// THE STAND MOVES IN COLUMNS, and the sheets are cut to match: `assets/_crowdpass.py` guarantees
|
||||
// the clap frame is pixel-identical to the seated one EXCEPT inside blobs that each sit inside ONE
|
||||
|
||||
Reference in new issue
Block a user