Merge remote-tracking branch 'origin/lane/e'

This commit is contained in:
m3ultra 2026-07-17 15:05:56 +10:00
commit e8fa8a736e
11 changed files with 260 additions and 35 deletions

View File

@ -2693,3 +2693,52 @@ Format: `[lane letter] YYYY-MM-DD — note`
on the record, A's "1 lost" was a miscount, and C found the REAL winnable line (p1,p2,p3,p4 — on the record, A's "1 lost" was a miscount, and C found the REAL winnable line (p1,p2,p3,p4 —
$80 exactly, hp 52, 1 lost) that needs B's porous fabric + C's 0.40 downdraft STACKED. The $80 exactly, hp 52, 1 lost) that needs B's porous fabric + C's 0.40 downdraft STACKED. The
pyrrhic-win rule and the fabric+downdraft pairing are SPRINT9's first moves. pyrrhic-win rule and the fabric+downdraft pairing are SPRINT9's first moves.
[E] 2026-07-18 — 🏚️ **`carport_01_v1.glb` — site_02's dressing, and its whole design (SPRINT9 §gate 2-E).**
3.24 × 5.60 × 2.69 m, 172 tris. DESIGN.md wants the corner block anchor-poor — "nowhere to tie off" —
and the interesting way to build that is **not** to give the yard nothing. An empty yard is just a
smaller yard. It's to give it something that LOOKS like four free anchors and isn't. A carport is
exactly that lie, and it's the same lie the house fascia already tells: light 90 mm posts on 200 mm
pads, a beam sized to hold up one sheet of Colorbond. Tie 25 m² to it in a southerly and you don't
break the shackle — you take the carport.
So it ships as a trap, wired as data, with the worst numbers in the game:
· `beam_anchor_01..02``rating_hint` **0.22**, `collateral="carport"` (the fascia is 0.35).
· `post_anchor_01..02`**0.30**. A pad is better than a beam; it's still a lie.
· plus `footings` / `posts` / `beams` / `roof`, and `is_anchor_trap` on the root.
**Lane A/B: these are meant to be TAKEN, and to hurt.** Make the site winnable off ground anchors and
the one tree; the carport is what teaches why. e.test.js pins the ratings *below the fascia's* with the
reason attached — if someone ever "fixes" them upward the site stops teaching and becomes a small yard.
**Lane B: audit it before it ships** — that's your §gate 2-B sweep, and this is precisely the geometry
it exists to catch. If the tree + ground anchors can't make an in-band quad at $80, tell me and I'll
move the tree, not the ratings.
[E] 2026-07-18 — **the pyrrhic ending has a card and words (gate 1-1, "E will want in").**
`models/textures/card_pyrrhic.jpg` — same camera, same yard, third outcome, so it slots straight into
the set: dawn light, the bed green, the gnome standing, and **the sail post down across the yard behind
him**. That's the reading in one frame — the rig let go, he didn't. Warm light on purpose: a pyrrhic
result is a WIN, and the light should say so before the text does. The wreckage is the price, not the
verdict.
Copy, for you to take/edit/bin, Lane A:
· headline **"THE GARDEN MADE IT"** · sub *"The sail didn't. That's the trade you took."*
· kicker *"A sail is a consumable. A season isn't."*
· alternates: "BOUGHT AND PAID FOR" / *"Two corners gone. The bed never knew."*
· per-night verdict line, if you want one: *"the sail took it so the bed didn't"*.
`tools/cardpreview/index.html` renders all three now — `show('win'|'pyrrhic'|'lose')`.
This is DESIGN.md's actual thesis finally having a picture: the sail was never the point.
[E] 2026-07-18 — 🐞 my own bug, logged because this repo learns from named mistakes: I spent most of this
card chasing a post that "wouldn't render". It rendered fine — I'd made **two** of them. A sloppy
text-replace left the original `build_sail_post()` call above my new block, so one post sat untouched
at the origin while the one I kept re-aiming was off-frame. Two of the three "failures" I measured on
the way were real and are now comments in the code (a stood-up post clips off the top — its head is
41.7° above the camera axis where the vertical half-FOV is 11.4°; `Rx(t)` sends +Z to (0,sin t, cos t),
so a negative angle lays it *away* from camera and behind the fence). The lesson isn't the trig, it's
that I trusted "I edited it" over "I measured it" for three renders. The probe took 30 seconds.
[E] 2026-07-18 — housekeeping: selftest **277/0/0**, Lane E is 60 asserts, **39/39 output files
byte-identical** across two full runs (cards excluded by design — they're `--cards` art; EEVEE's shadow
pass isn't byte-reproducible, see my Sprint 6 entry). Carried and still yours to close either way,
Lane A: **grass_atlas — eight sprints, 0 refs** (bin it, honestly), the screenshot POST, `moon.png`.
Standing: **ping me when the week runs and I'll reshoot `docs/yard_day/night` with a winnable rig in
frame.** And when A's `data/sites/*.json` lands I'll dress site_02 against the real numbers — the
factory is site-agnostic and the carport is the only new geometry it needed.

View File

@ -133,6 +133,28 @@
"status": "PASS", "status": "PASS",
"problems": [] "problems": []
}, },
{
"name": "carport_01",
"dims": [
3.24,
5.5959,
2.6945
],
"tris": 172,
"nodes": [
"beam_anchor_01",
"beam_anchor_02",
"beams",
"carport_01",
"footings",
"post_anchor_01",
"post_anchor_02",
"posts",
"roof"
],
"status": "PASS",
"problems": []
},
{ {
"name": "shed_01", "name": "shed_01",
"dims": [ "dims": [

View File

@ -781,6 +781,86 @@ def build_house_yardside(name):
return root return root
def build_carport_01(name):
"""A single-car carport — the corner block's whole personality (SPRINT9 §E).
DESIGN.md says that site is anchor-poor: "nowhere to tie off". The interesting
way to build that is NOT to give the yard nothing an empty yard is just a
smaller yard. It's to give it something that LOOKS like four free anchors and
isn't. A carport is exactly that lie, and it's the same lie the house fascia
tells: light C-section posts on shallow pads, a roof beam sized to hold up a
sheet of Colorbond and precisely nothing else. Tie a 25 sail to it in a
southerly and you don't break the shackle, you take the carport.
So the anchors ship with honest, terrible numbers:
· `beam_anchor_01..02` rating_hint 0.22, the worst in the game (the house
fascia is 0.35). collateral="carport": pull these and the roof goes.
· `post_anchor_01..02` 0.30. Better, because a post at least stands on a
pad, but it's still a 90 mm post in 200 mm of concrete.
Lane A/B: these are meant to be TAKEN and to hurt. The site is winnable off
ground anchors and the one tree; the carport is the trap that teaches why.
"""
root = add_empty(name)
steel = get_material("Mat_Steel", PAL["steel_gal"], 0.4, metallic=0.85)
dark = get_material("Mat_SteelDark", PAL["steel_dark"], 0.45, metallic=0.8)
sheet = get_material("Mat_Colorbond", PAL["colorbond"], 0.45, metallic=0.5)
conc = get_material("Mat_Concrete", PAL["concrete"], 0.95)
W, D = 3.0, 5.4 # one car, tight — it's a corner block
H_HI, H_LO = 2.45, 2.20 # skillion, falling away from the street
posts, pads = [], []
for sx in (-1, 1):
for sy in (-1, 1):
x, y = sx * (W / 2 - 0.09), sy * (D / 2 - 0.09)
h = H_HI if sy < 0 else H_LO
pads.append(add_box(f"{name}_pad_{sx}_{sy}", (0.26, 0.26, 0.09),
(x, y, 0.045), conc))
# 90 mm box section. Light, and meant to look it.
posts.append(add_box(f"{name}_post_{sx}_{sy}", (0.09, 0.09, h),
(x, y, h / 2 + 0.09), steel))
join_group(pads, "footings", root)
join_group(posts, "posts", root)
beams = []
for sy in (-1, 1):
h = H_HI if sy < 0 else H_LO
beams.append(add_box(f"{name}_beam_{sy}", (W, 0.05, 0.14),
(0, sy * (D / 2 - 0.09), h + 0.09), dark))
for sx in (-1, 1):
beams.append(add_tube_between(
f"{name}_rafter_{sx}",
(sx * (W / 2 - 0.09), -D / 2 + 0.09, H_HI + 0.16),
(sx * (W / 2 - 0.09), D / 2 - 0.09, H_LO + 0.16), 0.035, dark, verts=6))
join_group(beams, "beams", root)
fall = math.atan2(H_HI - H_LO, D)
join_group([add_box(f"{name}_roof", (W + 0.24, D + 0.20, 0.04),
(0, 0, (H_HI + H_LO) / 2 + 0.22), sheet,
rot=(fall, 0, 0))], "roof", root)
# The trap, wired as data. Numbers are deliberately the worst in the game.
for i, sx in enumerate((-1, 1)):
e = add_empty(f"beam_anchor_{i + 1:02d}",
(sx * (W / 2 - 0.09), 0.0, H_LO + 0.16), root, size=0.18)
e["anchor_type"] = "carport"
e["rating_hint"] = 0.22 # worse than the house fascia's 0.35
e["collateral"] = "carport"
e["why"] = "sized for one sheet of roofing; a loaded sail takes the lot"
for i, sy in enumerate((-1, 1)):
e = add_empty(f"post_anchor_{i + 1:02d}",
(-(W / 2 - 0.09), sy * (D / 2 - 0.09), 1.75), root, size=0.18)
e["anchor_type"] = "carport_post"
e["rating_hint"] = 0.30
e["collateral"] = "carport"
e["why"] = "90 mm post on a 200 mm pad — better than the beam, still a lie"
stamp(root, name, "structure")
root["site_hint"] = "corner_block"
root["is_anchor_trap"] = True
return root
def build_shed_01(name): def build_shed_01(name):
"""Colorbond garden shed, skillion roof. Spare hardware lives in here.""" """Colorbond garden shed, skillion roof. Spare hardware lives in here."""
root = add_empty(name) root = add_empty(name)
@ -1750,42 +1830,67 @@ def build_moon_texture():
# ============================================================================ # ============================================================================
# END CARDS — rendered from the game's own props, not drawn (SPRINT6 §Lane E-2) # END CARDS — rendered from the game's own props, not drawn (SPRINT6 §Lane E-2)
# ============================================================================ # ============================================================================
def _card_scene(broken): def _card_scene(state):
"""One vignette, built from the same yard objects the player spent the week """One vignette, built from the same yard objects the player spent the week
protecting that's the whole idea. A gradient with a font on it says protecting that's the whole idea. A gradient with a font on it says
nothing; the gnome you failed to protect, lying in pieces, says it without a nothing; the gnome you failed to protect, lying in pieces, says it without a
word.""" word.
Three endings, one camera (SPRINT9 gate 1 adds the pyrrhic):
· win everything stands, dawn. You got away with it.
· pyrrhic the bed is green and the gnome is fine, but a post is on its
face and the fence is gone. DESIGN.md's actual thesis: the sail is not
the point, the garden is, and a rig that dies saving it did its job.
Warm light, because you WON the wreckage is the price, not the verdict.
· lose gnome in bits, bed dead, flat grey. Nothing was saved.
"""
reset_to_empty() reset_to_empty()
grass = get_material("Mat_Grass", "#4A6B36" if broken else "#5C8A3A", 1.0) lost = state == "lose"
wrecked = state != "win" # the fence goes in both bad endings
grass = get_material("Mat_Grass", "#4A6B36" if lost else "#5C8A3A", 1.0)
add_box("ground", (60, 60, 0.4), (0, 0, -0.2), grass) add_box("ground", (60, 60, 0.4), (0, 0, -0.2), grass)
if broken: if lost:
gnome = build_garden_gnome_01_broken("gnome") gnome = build_garden_gnome_01_broken("gnome")
gnome.location = (0.82, -0.78, 0)
gnome.rotation_mode = 'XYZ' gnome.rotation_mode = 'XYZ'
gnome.rotation_euler = (0, 0, math.radians(-24)) gnome.rotation_euler = (0, 0, math.radians(-24))
fence = build_fence_panel_snapped("fence") else:
fence.location = (-0.35, 2.6, 0) gnome = build_garden_gnome_01("gnome")
bin_ = build_wheelie_bin_01("bin") # blown over, lid flung open gnome.location = (0.82, -0.78, 0)
bin_.location = (2.9, 1.5, 0.34)
bin_.rotation_mode = 'XYZ' fence = (build_fence_panel_snapped if wrecked else build_fence_panel)("fence")
bin_.rotation_euler = (math.radians(-96), 0, math.radians(38)) fence.location = (-0.35, 2.6, 0)
bed = build_garden_bed("bed")
bed.location = (-3.4, 1.2, 0) bed = build_garden_bed("bed")
for o in bpy.data.objects: # a loss shows the dead bed bed.location = (-3.4, 1.2, 0)
if lost:
for o in bpy.data.objects: # only a loss shows the dead bed
if o.name == "plants_full": if o.name == "plants_full":
o.hide_render = True o.hide_render = True
elif o.name == "plants_dead": elif o.name == "plants_dead":
o.hide_render = False o.hide_render = False
else:
gnome = build_garden_gnome_01("gnome") if state == "pyrrhic":
gnome.location = (0.82, -0.78, 0) # The post came out of the ground rather than the shackle letting go —
fence = build_fence_panel("fence") # DESIGN.md's "a post in wet ground pulls out slowly, with creaking".
fence.location = (-0.35, 2.6, 0) # Rotating the ROOT (not rake_pivot) tips the footing with it, which is
post = build_fence_post("post") # exactly right here: the concrete is out of the dirt.
post.location = (0.85, 2.6, 0) #
bed = build_garden_bed("bed") # Placement is the whole trick, and three measured failures got here:
bed.location = (-3.4, 1.2, 0) # stood up, the head sits 41.7 deg above the camera axis when the
# vertical half-FOV is 11.4, so it clips off the top; based at the fence
# line the footing hides behind the palings; and Rx(t) sends +Z to
# (0, -sin t, cos t), so a NEGATIVE angle lays it AWAY from camera and
# out of shot. Flat, forward of the fence, crossing behind the gnome:
# the rig let go, he didn't.
post = build_sail_post("post_down")
post.location = (2.60, 2.00, 0.05)
post.rotation_mode = 'XYZ'
post.rotation_euler = (math.radians(88), 0, math.radians(-60))
elif state == "win":
p = build_fence_post("post")
p.location = (0.85, 2.6, 0)
shed = build_shed_01("shed") shed = build_shed_01("shed")
shed.location = (3.6, 2.2, 0) shed.location = (3.6, 2.2, 0)
@ -1808,9 +1913,11 @@ def build_end_cards():
other lanes rely on. other lanes rely on.
""" """
out = [] out = []
for name, broken, warm in (("card_win", False, True), for name, state in (("card_win", "win"),
("card_gameover", True, False)): ("card_pyrrhic", "pyrrhic"),
_card_scene(broken) ("card_gameover", "lose")):
_card_scene(state)
warm = state != "lose"
scn = bpy.context.scene scn = bpy.context.scene
scn.render.engine = 'BLENDER_EEVEE' scn.render.engine = 'BLENDER_EEVEE'
scn.render.resolution_x, scn.render.resolution_y = 1200, 675 scn.render.resolution_x, scn.render.resolution_y = 1200, 675
@ -1821,7 +1928,8 @@ def build_end_cards():
bg = scn.world.node_tree.nodes.get("Background") bg = scn.world.node_tree.nodes.get("Background")
if bg: if bg:
# Dawn after a night you survived, vs the flat grey of a morning you # Dawn after a night you survived, vs the flat grey of a morning you
# have to explain to a client. # have to explain to a client. The pyrrhic card gets the dawn: it is
# a win, and the light should say so before the text does.
bg.inputs[0].default_value = ((0.92, 0.55, 0.32, 1.0) if warm bg.inputs[0].default_value = ((0.92, 0.55, 0.32, 1.0) if warm
else (0.34, 0.37, 0.41, 1.0)) else (0.34, 0.37, 0.41, 1.0))
# Low strength on purpose. The world is a huge ambient fill, and at # Low strength on purpose. The world is a huge ambient fill, and at
@ -1843,11 +1951,11 @@ def build_end_cards():
cam = _active() cam = _active()
cam.data.lens = 50 cam.data.lens = 50
scn.camera = cam scn.camera = cam
# IDENTICAL camera on both cards, deliberately. They're a diptych: same # IDENTICAL camera on every card, deliberately. They're a set: same yard,
# yard, same framing, and the only thing that changed overnight is what # same framing, and the only thing that changed overnight is what happened
# happened to it. A player who sees both reads the difference instantly, # to it. A player who has seen one reads the next instantly, which no
# which no amount of headline text would do as fast. Low and close, so # amount of headline text would do as fast. Low and close, so the gnome is
# the gnome is the subject; the left third stays empty for Lane A's text. # the subject; the left third stays empty for Lane A's text.
cam.location = (2.00, -2.86, 0.94) cam.location = (2.00, -2.86, 0.94)
cam.rotation_mode = 'XYZ' cam.rotation_mode = 'XYZ'
target = Vector((0.66, -0.42, 0.30)) target = Vector((0.66, -0.42, 0.30))
@ -1940,6 +2048,12 @@ ASSETS = [
nodes=["wall", "door", "window", "roof", "fascia", "gutter", nodes=["wall", "door", "window", "roof", "fascia", "gutter",
"window_glow", "window_light_anchor", "window_glow", "window_light_anchor",
"fascia_anchor_01", "fascia_anchor_02", "fascia_anchor_03"]), "fascia_anchor_01", "fascia_anchor_02", "fascia_anchor_03"]),
# site_02 (corner block): the anchor trap, not just dressing.
dict(name="carport_01", fn=build_carport_01,
dims=((3.0, 3.5), (5.2, 5.8), (2.4, 2.8)),
nodes=["footings", "posts", "beams", "roof",
"beam_anchor_01", "beam_anchor_02",
"post_anchor_01", "post_anchor_02"]),
dict(name="shed_01", fn=build_shed_01, dict(name="shed_01", fn=build_shed_01,
dims=((2.4, 2.7), (1.8, 2.1), (1.95, 2.25)), dims=((2.4, 2.7), (1.8, 2.1), (1.95, 2.25)),
nodes=["shell", "roof", "doors", "door_anchor"]), nodes=["shell", "roof", "doors", "door_anchor"]),

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

After

Width:  |  Height:  |  Size: 3.0 MiB

View File

@ -19,8 +19,9 @@
font: 14px/1.55 ui-monospace, SFMono-Regular, Menlo, monospace; font: 14px/1.55 ui-monospace, SFMono-Regular, Menlo, monospace;
color: #fff; color: #fff;
} }
.endcard.win { background-image: url('/web/world/models/textures/card_win.jpg'); } .endcard.win { background-image: url('/web/world/models/textures/card_win.jpg'); }
.endcard.lose { background-image: url('/web/world/models/textures/card_gameover.jpg'); } .endcard.pyrrhic { background-image: url('/web/world/models/textures/card_pyrrhic.jpg'); }
.endcard.lose { background-image: url('/web/world/models/textures/card_gameover.jpg'); }
/* The art was framed with its left third deliberately empty. This scrim only /* The art was framed with its left third deliberately empty. This scrim only
deepens what's already there, so the text has something to sit on without deepens what's already there, so the text has something to sit on without
@ -35,7 +36,8 @@
margin: 0 0 10px; font-size: clamp(30px, 4.4vw, 52px); line-height: .98; margin: 0 0 10px; font-size: clamp(30px, 4.4vw, 52px); line-height: .98;
letter-spacing: .06em; font-weight: 800; letter-spacing: .06em; font-weight: 800;
} }
.endcard.win h1 { color: #ffd9a3; text-shadow: 0 2px 26px rgba(255,150,60,.45); } .endcard.win h1,
.endcard.pyrrhic h1 { color: #ffd9a3; text-shadow: 0 2px 26px rgba(255,150,60,.45); }
.endcard.lose h1 { color: #e8edf2; text-shadow: 0 2px 22px rgba(0,0,0,.7); } .endcard.lose h1 { color: #e8edf2; text-shadow: 0 2px 22px rgba(0,0,0,.7); }
.endcard .sub { margin: 0 0 18px; font-size: clamp(14px, 1.5vw, 18px); color: #dfe6ec; } .endcard .sub { margin: 0 0 18px; font-size: clamp(14px, 1.5vw, 18px); color: #dfe6ec; }
.endcard .kicker { .endcard .kicker {
@ -60,6 +62,7 @@
<!-- Toggle for eyeballing; not part of the snippet. --> <!-- Toggle for eyeballing; not part of the snippet. -->
<div style="position:fixed;z-index:60;right:12px;top:12px;display:flex;gap:8px"> <div style="position:fixed;z-index:60;right:12px;top:12px;display:flex;gap:8px">
<button onclick="show('win')" style="font:12px ui-monospace;padding:8px 12px">win</button> <button onclick="show('win')" style="font:12px ui-monospace;padding:8px 12px">win</button>
<button onclick="show('pyrrhic')" style="font:12px ui-monospace;padding:8px 12px">pyrrhic</button>
<button onclick="show('lose')" style="font:12px ui-monospace;padding:8px 12px">game over</button> <button onclick="show('lose')" style="font:12px ui-monospace;padding:8px 12px">game over</button>
</div> </div>
@ -86,6 +89,15 @@ const COPY = {
['hardware lost', '2 shackles'], ['collateral', '$25 (gnome)'], ['hardware lost', '2 shackles'], ['collateral', '$25 (gnome)'],
['bank', '$164', true]], ['bank', '$164', true]],
}, },
pyrrhic: {
h: 'THE GARDEN MADE IT',
s: "The sail didn't. That's the trade you took.",
k: 'A sail is a consumable. A season isn\'t.',
b: 'NEXT WEEK',
rows: [['nights survived', '5 / 5'], ['garden, worst night', '52%'],
['corners lost', '2 (t2, p3)'], ['hardware lost', '1 shackle, 1 carabiner'],
['bank', '$88', true]],
},
lose: { lose: {
h: 'OFF THE JOB', h: 'OFF THE JOB',
s: 'Broke, with the week still running.', s: 'Broke, with the week still running.',

View File

@ -80,6 +80,9 @@ const ASSETS = [
{ name: 'broom_01', h: [1.35, 1.50], { name: 'broom_01', h: [1.35, 1.50],
nodes: ['handle', 'head', 'bristles', 'grip_anchor', 'poke_tip'] }, nodes: ['handle', 'head', 'bristles', 'grip_anchor', 'poke_tip'] },
{ name: 'hail_stone_01', h: [0.012, 0.028], nodes: ['stone'] }, { name: 'hail_stone_01', h: [0.012, 0.028], nodes: ['stone'] },
{ name: 'carport_01', h: [2.4, 2.8],
nodes: ['footings', 'posts', 'beams', 'roof',
'beam_anchor_01', 'beam_anchor_02', 'post_anchor_01', 'post_anchor_02'] },
]; ];
function sizeOf(gltf) { function sizeOf(gltf) {
@ -144,6 +147,31 @@ export default async function run(t) {
}); });
} }
// site_02's whole personality is "nowhere to tie off", and it lives in these
// four numbers rather than in any geometry. The carport is meant to LOOK like
// four free anchors and be the worst steel in the game — worse even than the
// house fascia, which DESIGN.md already calls a lie. If someone quietly
// "fixes" these ratings upward the site stops teaching anything and just
// becomes a smaller yard, so they're pinned here with the reason attached.
t.test('carport anchors stay a trap — the corner block has no good tie-off', () => {
const g = loaded.get('carport_01');
assert(g, 'carport_01 did not load');
const FASCIA = 0.35; // house_yardside's, the previous worst
for (const n of ['beam_anchor_01', 'beam_anchor_02']) {
const o = g.scene.getObjectByName(n);
assert(o, `${n} missing`);
assert(o.userData?.rating_hint < FASCIA,
`${n} rates ${o.userData?.rating_hint} — the carport beam must be worse than the fascia (${FASCIA})`);
assert(o.userData?.collateral === 'carport',
`${n} must carry collateral="carport" — taking it takes the roof`);
}
for (const n of ['post_anchor_01', 'post_anchor_02']) {
const o = g.scene.getObjectByName(n);
assert(o?.userData?.rating_hint < FASCIA,
`${n} rates ${o?.userData?.rating_hint} — still a 90 mm post on a small pad`);
}
});
// These five numbers are load-bearing for the whole repo: Lane A's winning // These five numbers are load-bearing for the whole repo: Lane A's winning
// line rigs off t2, and every balance figure B and C measured assumes the // line rigs off t2, and every balance figure B and C measured assumes the
// branch anchors sit exactly here. I reshaped the limbs in Sprint 7 for looks // branch anchors sit exactly here. I reshaped the limbs in Sprint 7 for looks

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB