This commit is contained in:
2026-01-19 13:06:59 -08:00
parent 616c8184d0
commit 00f2243f03

View File

@@ -125,7 +125,7 @@
<!-- <polygon class="wall" points="-10,50 -3,50 -3,60 -10,60" /> -->
<!-- <polygon class="wall" points="20,-50 10,-50 10,-60 20,-60" /> -->
<!-- <polygon class="wall" points="-20,50 -10,50 -10,60 -20,60" /> -->
<polygon class="wall" points="-10,10 10,10 10,20 -10,20" />
<!-- <polygon class="wall" points="-20,-50 -10,-50 -10,-60 -20,-60" /> -->
<!-- <polygon class="wall" points="20,50 10,50 10,60 20,60" /> -->
@@ -136,11 +136,11 @@
<!-- <polygon class="wall" points="10,50 100,50 100,60 10,60" /> -->
<!-- <polygon class="wall" points="34,56 56,78 45,98 23,89" /> -->
<polygon class="wall" points="44,55 55,66 33,88 22,66" />
<polygon class="wall" points="-55,-44 -33,-33 -55,-22 -66,-33" />
<polygon class="wall" points="77,-22 133,-6 99,0 88,-5" />
<polygon class="wall" points="-77,99 -66,88 -44,122 -88,133" />
<polygon class="wall" points="-99,44 -77,44 -88,55" />
<!-- <polygon class="wall" points="44,55 55,66 33,88 22,66" /> -->
<!-- <polygon class="wall" points="-55,-44 -33,-33 -55,-22 -66,-33" /> -->
<!-- <polygon class="wall" points="77,-22 133,-6 99,0 88,-5" /> -->
<!-- <polygon class="wall" points="-77,99 -66,88 -44,122 -88,133" /> -->
<!-- <polygon class="wall" points="-99,44 -77,44 -88,55" /> -->
<!-- <polygon class="wall" points="-50,50 -40,60 -50,70 -60,60" /> -->
<!-- <polygon class="wall" points="50,-30 40,-60 50,-70 60,-60" /> -->
@@ -176,9 +176,10 @@
<div id="info" xmlns="http://www.w3.org/1999/xhtml">
<span id="time" xmlns="http://www.w3.org/1999/xhtml">0</span> s
<span id="fps" xmlns="http://www.w3.org/1999/xhtml">-</span> fps
<br/>
<span id="position" xmlns="http://www.w3.org/1999/xhtml">-,-</span> x,y position
</div>
<ul xmlns="http://www.w3.org/1999/xhtml">
<li xmlns="http://www.w3.org/1999/xhtml">use angular velocity for gun turning?</li>
<li xmlns="http://www.w3.org/1999/xhtml">bounce from collisions</li>
<li xmlns="http://www.w3.org/1999/xhtml">fall off screen after crash</li>
<li xmlns="http://www.w3.org/1999/xhtml">make ship a helicopter</li>
@@ -188,6 +189,7 @@
<li xmlns="http://www.w3.org/1999/xhtml">additional cannon firing modes</li>
<li xmlns="http://www.w3.org/1999/xhtml">keep ship position at 0,0 actual</li>
<li xmlns="http://www.w3.org/1999/xhtml">only start on movement not just any keypress</li>
<li xmlns="http://www.w3.org/1999/xhtml">draw a parabolic line for bullet trajectory in gravity?</li>
</ul>
<pre id="debug" xmlns="http://www.w3.org/1999/xhtml"></pre>
<div id="pointer" xmlns="http://www.w3.org/1999/xhtml">
@@ -197,24 +199,315 @@
</foreignObject>
<script type="text/javascript">//<![CDATA[
const zeroP = { x: 0, y: 0 };
// entities
// const Ships = [{ entity_id: "ship_1" }];
const Ships = [{ entity_id: "ship1" }];
// const Walls = [{ entity_id: "wall_1" }, { entity_id: "wall_2" }];
// systems
// Move.update = ({ entity_id }) => {
// reads Velocity[entity_id]
// sets Position[entity_id]
// };
// components
// Velocity = { "ship_1": { x: 0, y: 0 }};
// Position = { "ship_1": { x: 0, y: 0 }};
const Velocity = {};
const Position = {};
const Acceleration = {};
// Ships.forEach(({ entity_id }) => {
// Acceleration[entity_id] = zeroP;
// Velocity[entity_id] = zeroP;
// Position[entity_id] = zeroP;
// });
// Points = {
// "wall_1": "0,0 2,0 1,1",
// "wall_2": "0,0 -1,1 -2,0",
// };
// systems
const Move = (() => {
const metersPerMillisecond = 0.001;
// Triangle has a clockwise orientation
function isClockwise([xa, ya], [xb, yb], [xc, yc]) {
// https://en.wikipedia.org/wiki/Curve_orientation#Practical_considerations
// Determinant for a convex polygon
const det = (xb - xa) * (yc - ya) - (xc - xa) * (yb - ya);
return det < 0;
}
function isAcute([xa, ya], [xb, yb], [xc, yc]) {
const da = distance(xa, ya, xc, yc);
const db = distance(xb, yb, xc, yc);
const dc = distance(xa, ya, xb, yb);
// https://en.wikipedia.org/wiki/Law_of_cosines
// Solve for angles alpha and beta with inverse cosine (arccosine)
const alpha = Math.acos((db ** 2 + dc ** 2 - da ** 2) / (2 * db * dc));
const beta = Math.acos((da ** 2 + dc ** 2 - db ** 2) / (2 * da * dc));
return alpha < halfPi && beta < halfPi;
}
function getForwardEdges(edges, { x, y }) {
return edges.filter(({ edge: { xa, ya, xb, yb } }) =>
isClockwise([xa, ya], [xb, yb], [x, y]) && isAcute([xa, ya], [xb, yb], [x, y]));
}
function getForwardCorners(corners, position, velocity) {
const { x: x1, y: y1 } = position;
const { x: x2, y: y2 } = velocity;
const { x: vx, y: vy } = velocity;
let perppts = {};
if (vx === 0 && vy === 0) {
// none
} else if (vx === 0 && vy > 0) {
perppts = { a: { x: x1 - 1, y: y1 }, b: { x: x1 + 1, y: y1 }};
} else if (vx === 0 && vy < 0) {
perppts = { a: { x: x1 + 1, y: y1 }, b: { x: x1 - 1, y: y1 }};
} else if (vy === 0 && vx > 0) {
perppts = { a: { x: x1, y: y1 + 1 }, b: { x: x1, y: y1 - 1 }};
} else if (vy === 0 && vx < 0) {
perppts = { a: { x: x1, y: y1 - 1 }, b: { x: x1, y: y1 + 1 }};
} else if (vy > 0 && vx > 0) {
const vslope = vy / vx;
const pslope = 1 / -vslope;
// Point-slope line equation
const pya = pslope * (x1 - 1) - pslope * x1 + y1;
const pyb = pslope * (x1 + 1) - pslope * x1 + y1;
perppts = { a: { x: x1 - 1, y: pya }, b: { x: x1 + 1, y: pyb }};
} else if (vy > 0 && vx < 0) {
const vslope = vy / vx;
const pslope = 1 / -vslope;
const pya = pslope * (x1 - 1) - pslope * x1 + y1;
const pyb = pslope * (x1 + 1) - pslope * x1 + y1;
perppts = { a: { x: x1 - 1, y: pya }, b: { x: x1 + 1, y: pyb }};
} else if (vy < 0 && vx > 0) {
const vslope = vy / vx;
const pslope = 1 / -vslope;
const pya = pslope * (x1 + 1) - pslope * x1 + y1;
const pyb = pslope * (x1 - 1) - pslope * x1 + y1;
perppts = { a: { x: x1 + 1, y: pya }, b: { x: x1 - 1, y: pyb }};
} else if (vy < 0 && vx < 0) {
const vslope = vy / vx;
const pslope = 1 / -vslope;
const pya = pslope * (x1 + 1) - pslope * x1 + y1;
const pyb = pslope * (x1 - 1) - pslope * x1 + y1;
perppts = { a: { x: x1 + 1, y: pya }, b: { x: x1 - 1, y: pyb }};
} else {
//
}
const { a, b } = perppts;
// if (a && b) drawLine(a.x, a.y, b.x, b.y);
return corners.filter(({ corner: c }) => {
if (!a || !b) return;
const det = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
return det > 0;
});
}
function getEdgeCollisionBoundary(edge, dist) {
const { xa, ya, xb, yb } = edge;
const length = distance(xa, ya, xb, yb);
const rise = yb - ya;
const run = xb - xa;
const riol = rise / length * dist;
const ruol = run / length * dist;
return { xa: xa + riol, ya: ya - ruol, xb: xb + riol, yb: yb - ruol};
}
function detectEdgeCollision([xc, yc], [x, y], radius, gearDown) {
// console.log("*detectEdgeCollision", xc, yc, x, y, radius, gearDown);
return (collision) => {
if (xc === x && yc === y) return;
const { edge, wall } = collision;
const dist = edge.xa < edge.xb && edge.ya === edge.yb && gearDown ? radius + 1.5 : radius;
const edgeSeg = getEdgeCollisionBoundary(edge, dist);
const positionSeg = { xa: x, ya: y, xb: xc, yb: yc };
const { xa: x1, ya: y1, xb: x2, yb: y2 } = positionSeg;
const { xa: x3, ya: y3, xb: x4, yb: y4 } = edgeSeg;
// https://en.wikipedia.org/wiki/Intersection_(geometry)#Two_line_segments
// https://en.wikipedia.org/wiki/Cramer%27s_rule#Explicit_formulas_for_small_systems
const s = ((x3-x1)*(y4-y3)-(x4-x3)*(y3-y1))/((x2-x1)*(y4-y3)-(x4-x3)*(y2-y1));
const t = -((x2-x1)*(y3-y1)-(x3-x1)*(y2-y1))/((x2-x1)*(y4-y3)-(x4-x3)*(y2-y1));
const roundedT = +t.toFixed(2);
const roundedS = +s.toFixed(2);
if (roundedS >= 0 && roundedS <= 1 && roundedT >= 0 && roundedT <= 1) {
const xs = (x1 + s * (x2 - x1));
const ys = (y1 + s * (y2 - y1));
collision.position = { x: xs, y: ys };
return true;
}
// return roundedS >= 0 && roundedS <= 1 && roundedT >= 0 && roundedT <= 1;
return;
};
}
function perpIntxn(baseSlope, xa, ya, xc, yc) {
let isx, isy;
// base is vertical
if (baseSlope === -Infinity || baseSlope === Infinity) {
isx = xa;
isy = yc;
} else if (baseSlope === 0) { // base is horizontal
isx = xc;
isy = ya;
} else {
const altitudeSlope = 1 / -baseSlope;
isx = (-altitudeSlope * xc + yc + baseSlope * xa - ya) / (baseSlope - altitudeSlope);
isy = altitudeSlope * isx - altitudeSlope * xc + yc;
}
return { x: isx, y: isy };
}
function slope({ xa, ya, xb, yb }) {
return (yb - ya) / (xb - xa);
}
function distance(x1, y1, x2, y2) {
return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
}
function detectCornerCollision([xc, yc], [x, y], radius) {
return c => {
if (xc === x && yc === y) return;
const d = distance(c.corner.x, c.corner.y, xc, yc);
if (d <= radius) return true;
const positionSeg = { xa: xc, ya: yc, xb: x, yb: y };
const posNormIntxn = perpIntxn(slope(positionSeg), x, y, c.corner.x, c.corner.y);
const cornerSeg = { xa: c.corner.x, ya: c.corner.y, xb: posNormIntxn.x, yb: posNormIntxn.y };
const { x: x0, y: y0 } = c.corner;
const { xa: x1, ya: y1, xb: x2, yb: y2 } = positionSeg;
const { xa: x3, ya: y3, xb: x4, yb: y4 } = cornerSeg;
// https://en.wikipedia.org/wiki/Intersection_(geometry)#Two_line_segments
// https://en.wikipedia.org/wiki/Cramer%27s_rule#Explicit_formulas_for_small_systems
const s = ((x3-x1)*(y4-y3)-(x4-x3)*(y3-y1))/((x2-x1)*(y4-y3)-(x4-x3)*(y2-y1));
const t = -((x2-x1)*(y3-y1)-(x3-x1)*(y2-y1))/((x2-x1)*(y4-y3)-(x4-x3)*(y2-y1));
const roundedT = +t.toFixed(2);
if (s >= 0 && roundedT <= 1) {
const xs = (x1 + s * (x2 - x1));
const ys = (y1 + s * (y2 - y1));
const xt = (x3 + roundedT * (x4 - x3));
const yt = (y3 + roundedT * (y4 - y3));
// [xs, ys] and [xt, yt] should be equal ([xs, ys] === [xy, yt])
// (...or about equal, notwithstanding rounding errors)
const sCollisionPt = [xs, ys];
const tCollisionPt = [xt, yt];
// drawCircle(posNormIntxn.x, posNormIntxn.y, "red");
// drawCircle(...tCollisionPt, "blue");
}
return s >= 0 && roundedT <= 1;
};
}
function withinCollisionDistance({ x: x1, y: y1 }, { x: x2, y: y2 }, distance) {
const diffx = x2;
const diffy = y2;
const detv = x2 * y1 - y2 * x1;
const dv = Math.sqrt(diffy ** 2 + diffx ** 2);
const slopev = slope({ xa: x1, ya: y1, xb: x1 + x2, yb: y1 + y2 });
return ({ corner: { x: x0, y: y0 }}) => {
const velNormIntxn = perpIntxn(slopev, x1, y1, x0, y0);
const dx = Math.max(x0, velNormIntxn.x) - Math.min(x0, velNormIntxn.x);
const dy = Math.max(y0, velNormIntxn.y) - Math.min(y0, velNormIntxn.y);
const d = Math.sqrt(dy ** 2 + dx ** 2);
return d <= distance;
};
}
function detectContacts(currentPos, intendedPos, velocity, radius, { edges, corners }, gearDown) {
const { x: xc, y: yc } = intendedPos;
const [x, y] = currentPos;
// edges oriented clockwise with entity
const fwdEdges = getForwardEdges(edges, { x, y });
// console.log("forward edges", fwdEdges);
const edgeColl = fwdEdges.filter(detectEdgeCollision([xc, yc], [x, y], radius, gearDown));
// console.log("edgeColl", edgeColl);
// corners ahead of ship
const fwdCorners = getForwardCorners(corners, { x, y }, velocity);
const cornersInPath = fwdCorners.filter(withinCollisionDistance({ x, y }, velocity, radius));
const cornerColl = cornersInPath.filter(detectCornerCollision([xc, yc], [x, y], radius));
return [...edgeColl, ...cornerColl];
}
return {
update: ({ entity_id }, elapsed) => {
const { x: px, y: py } = Position[entity_id];
const { x: vx, y: vy } = Velocity[entity_id];
const { x: ax, y: ay } = Acceleration[entity_id];
const v = {
x: vx > 0 && vx + ax <= 0 ? 0 : vx + ax,
y: vy > 0 && vy + ay <= 0 ? 0 : vy + ay
};
const p = {
x: px + elapsed * v.x * metersPerMillisecond,
y: py + elapsed * v.y * metersPerMillisecond
};
const contacts = detectContacts([px, py], p, v, s.radius, map, false);
console.log("CONTACTS", contacts);
if (contacts.length !== 0) {
console.log("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
let posP;
const contact = contacts[0];
if (contact.corner) {
posP = cornerContactPosition(p.x, p.y, px, py, contact.corner, s.radius);
} else if (contact.edge) {
// if (isLandable(contact.edge) && s.gearDown) s.isLanded = true;
// console.log("contact", contact);
posP = contact.position;
}
Velocity[entity_id] = { x: 0, y: 0 };
Position[entity_id] = { x: posP.x, y: posP.y };
// s.node.style.transform = `translate(${Position[entity_id].x}px, ${Position[entity_id].y}px)`;
// } else if (current && s.collision) {
// console.log("2222222222222222222222222222222");
// if (s.isLanded && s.velocity.y < 0) {
// s.gearDown = false;
// s.isLanded = false;
// s.position = { x: p.x, y: p.y };
// s.node.style.transform = `translate(${s.position.x}px, ${s.position.y}px)`;
// s.collision = null;
// } else {
// s.velocity = { x: 0, y: 0 };
// }
} else {
Velocity[entity_id] = { x: v.x, y: v.y };
Position[entity_id] = { x: p.x, y: p.y };
}
}
};
})();
const namespaceURIsvg = 'http://www.w3.org/2000/svg';
const bullets = [];
const halfPi = Math.PI / 2;
@@ -235,6 +528,7 @@ const svg = document.querySelector('svg');
const bg = svg.querySelector('#bg');
const fps = document.querySelector("#fps");
const time = document.querySelector("#time");
const positionEl = document.querySelector("#position");
const debug = document.querySelector("#debug");
const wallElements = document.querySelectorAll('.wall');
const bulletsContainer = document.querySelector("#bullets");
@@ -294,13 +588,24 @@ function init() {
started = false;
const mult = 10;
s.position = { x: 10, y: 10 };
s.position = { x: 0, y: 0 };
// s.velocity = { x: 0, y: -10 };
s.velocity = { x: 0, y: 0 };
s.angularVelocity = 0;
// s. velocity = { x: -5*mult, y: 7*mult };
s.acceleration = { x: 0, y: 0 };
Ships.forEach(({ entity_id }) => {
// Acceleration[entity_id] = s.acceleration;
// Velocity[entity_id] = s.velocity;
// Position[entity_id] = s.position;
Acceleration[entity_id] = { x: s.acceleration.x, y: s.acceleration.y };
Velocity[entity_id] = { x: s.velocity.x, y: s.velocity.y };
Position[entity_id] = { x: s.position.x, y: s.position.y };
});
s.angularAcceleration = 0;
s.rotate = 0;
s.degrees = 0;
@@ -360,11 +665,8 @@ function isAcute([xa, ya], [xb, yb], [xc, yc]) {
}
function getForwardEdges(edges, { x, y }) {
return edges.filter(({ edge }) => {
const { xa, ya, xb, yb } = edge;
const det = (xb - xa) * (y - ya) - (x - xa) * (yb - ya);
return det < 0;
});
return edges.filter(({ edge: { xa, ya, xb, yb } }) =>
isClockwise([xa, ya], [xb, yb], [x, y]) && isAcute([xa, ya], [xb, yb], [x, y]));
}
function getForwardCorners(corners, position, velocity) {
@@ -621,6 +923,8 @@ function getEdgeCollisionBoundary(edge, dist) {
}
function detectEdgeCollision([xc, yc], [x, y], radius, gearDown) {
// console.log("detectEdgeCollision", xc, yc, x, y, radius, gearDown);
return (collision) => {
if (xc === x && yc === y) return;
const { edge, wall } = collision;
@@ -786,7 +1090,8 @@ function lineIntxnPt({ x1, y1, x2, y2 }, { x1: x3, y1: y3, x2: x4, y2: y4 }) {
}
function updateShip(s, elapsed) {
const gravity = 0.25;
// const gravity = 0.25;
const gravity = 0;
// if (rotate > 0) {
// s.degrees = (s.degrees + rotationSpeed * elapsed) % 360;
@@ -805,11 +1110,16 @@ function updateShip(s, elapsed) {
const degrees = s.degrees;
ay += gravity;
console.log("s.acceleration", ax, ay);
s.velocity = {
x: vx > 0 && vx + ax <= 0 ? 0 : vx + ax,
y: vy > 0 && vy + ay <= 0 ? 0 : vy + ay
};
console.log("s.v", s.velocity.x, s.velocity.y);
s.angularVelocity = angularVel + angularAcc;
const friction = 0.05;
@@ -852,7 +1162,8 @@ function updateShip(s, elapsed) {
legs.style.display = s.gearDown ? "initial" : "none";
if (!current && s.collision) {
if (s.collision) {
// console.log("111111111111111111111111111");
let posP;
if (s.collision.corner) {
posP = cornerContactPosition(p.x, p.y, px, py, s.collision.corner, s.radius);
@@ -862,20 +1173,25 @@ function updateShip(s, elapsed) {
posP = s.collision.position;
}
s.velocity = { x: 0, y: 0 };
s.position = { x: posP.x, y: posP.y }
s.node.style.transform = `translate(${s.position.x}px, ${s.position.y}px)`;
} else if (current && s.collision) {
if (s.isLanded && s.velocity.y < 0) {
s.gearDown = false;
s.isLanded = false;
// s.velocity = { x: 0, y: 0 };
// s.position = { x: posP.x, y: posP.y }
s.position = { x: p.x, y: p.y };
s.node.style.transform = `translate(${s.position.x}px, ${s.position.y}px)`;
s.collision = null;
} else {
s.velocity = { x: 0, y: 0 };
}
// } else if (current && s.collision) {
// console.log("2222222222222222222222222222222");
// if (s.isLanded && s.velocity.y < 0) {
// s.gearDown = false;
// s.isLanded = false;
// s.position = { x: p.x, y: p.y };
// s.node.style.transform = `translate(${s.position.x}px, ${s.position.y}px)`;
// s.collision = null;
// } else {
// s.velocity = { x: 0, y: 0 };
// }
} else {
// console.log("33333333333333333333333333333");
s.position = { x: p.x, y: p.y };
s.node.style.transform = `translate(${s.position.x}px, ${s.position.y}px)`;
}
@@ -974,15 +1290,25 @@ function animate(timestamp) {
}
updateShip(s, elapsed);
// Move.update(Ships[0], elapsed);
Ships.forEach(({ entity_id }) => {
// Acceleration[entity_id] = zeroP;
// Velocity[entity_id] = zeroP;
// Position[entity_id] = zeroP;
Move.update({ entity_id }, elapsed);
});
positionEl.innerText = `${Position[Ships[0].entity_id].x.toFixed(1)},${Position[Ships[0].entity_id].y.toFixed(1)}`;
// updateEdges(position);
if (drawCollisionLines) updateTriangles(position);
if (s.collision && !s.isLanded) {
started = false;
isReadingKeys = false;
s.collision.wall.node.setAttribute('fill', 'red');
}
// stop game if ship touches a wall
// if (s.collision && !s.isLanded) {
// started = false;
// isReadingKeys = false;
// s.collision.wall.node.setAttribute('fill', 'red');
// }
if (restart) {
started = false;
@@ -1011,6 +1337,7 @@ let leftPressed = false;
let rightPressed = false;
let rotateCWPressed = false;
let rotateCCWPressed = false;
const { entity_id } = Ships[0];
document.addEventListener("keydown", function(e) {
if (!isReadingKeys) return;
@@ -1033,6 +1360,7 @@ document.addEventListener("keydown", function(e) {
if (!upPressed) {
upPressed = true;
s.acceleration.y += -force;
Acceleration[entity_id].y += -force;
}
break;
case "KeyS":
@@ -1040,6 +1368,7 @@ document.addEventListener("keydown", function(e) {
if (!downPressed) {
downPressed = true;
s.acceleration.y += force;
Acceleration[entity_id].y += force;
}
break;
case "KeyA":
@@ -1047,6 +1376,7 @@ document.addEventListener("keydown", function(e) {
if (!leftPressed) {
leftPressed = true;
if (!s.gearDown) s.acceleration.x += -force;
if (!s.gearDown) Acceleration[entity_id].x += -force;
}
break;
case "KeyD":
@@ -1054,6 +1384,7 @@ document.addEventListener("keydown", function(e) {
if (!rightPressed) {
rightPressed = true;
if (!s.gearDown) s.acceleration.x += force;
if (!s.gearDown) Acceleration[entity_id].x += force;
}
break;
case "KeyQ":
@@ -1093,6 +1424,7 @@ document.addEventListener("keyup", function(e) {
if (upPressed) {
upPressed = false;
s.acceleration.y -= -force;
Acceleration[entity_id].y -= -force;
}
break;
case "KeyS":
@@ -1100,6 +1432,7 @@ document.addEventListener("keyup", function(e) {
if (downPressed) {
downPressed = false;
s.acceleration.y -= force;
Acceleration[entity_id].y -= force;
}
break;
case "KeyA":
@@ -1107,6 +1440,7 @@ document.addEventListener("keyup", function(e) {
if (leftPressed) {
leftPressed = false;
if (!s.gearDown) s.acceleration.x -= -force;
if (!s.gearDown) Acceleration[entity_id].x -= -force;
}
break;
case "KeyD":
@@ -1114,6 +1448,7 @@ document.addEventListener("keyup", function(e) {
if (rightPressed) {
rightPressed = false;
if (!s.gearDown) s.acceleration.x -= force;
if (!s.gearDown) Acceleration[entity_id].x -= force;
}
break;
case "KeyQ":

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 47 KiB