@lichess-org/pgn-viewer 2.5.4 → 2.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2698,12 +2698,12 @@ var defaultTranslations = {
2698
2698
  "san.shortCastling": "short castling"
2699
2699
  };
2700
2700
 
2701
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/types.js
2701
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/types.js
2702
2702
  var colors = ["white", "black"];
2703
2703
  var files = ["a", "b", "c", "d", "e", "f", "g", "h"];
2704
2704
  var ranks = ["1", "2", "3", "4", "5", "6", "7", "8"];
2705
2705
 
2706
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/util.js
2706
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/util.js
2707
2707
  var invRanks = [...ranks].reverse();
2708
2708
  var allKeys = files.flatMap((f) => ranks.map((r) => f + r));
2709
2709
  var pos2key = (pos) => pos.every((x) => x >= 0 && x <= 7) ? allKeys[8 * pos[0] + pos[1]] : void 0;
@@ -2797,7 +2797,6 @@ var rookDir = (x1, y1, x2, y2) => x1 === x2 !== (y1 === y2);
2797
2797
  var bishopDir = (x1, y1, x2, y2) => diff(x1, x2) === diff(y1, y2) && x1 !== x2;
2798
2798
  var queenDir = (x1, y1, x2, y2) => rookDir(x1, y1, x2, y2) || bishopDir(x1, y1, x2, y2);
2799
2799
  var kingDirNonCastling = (x1, y1, x2, y2) => Math.max(diff(x1, x2), diff(y1, y2)) === 1;
2800
- var pawnDirCapture = (x1, y1, x2, y2, isDirectionUp) => diff(x1, x2) === 1 && y2 === y1 + (isDirectionUp ? 1 : -1);
2801
2800
  var pawnDirAdvance = (x1, y1, x2, y2, isDirectionUp) => {
2802
2801
  const step2 = isDirectionUp ? 1 : -1;
2803
2802
  return x1 === x2 && (y2 === y1 + step2 || // allow 2 squares from first two ranks, for horde
@@ -2818,20 +2817,6 @@ var squaresBetween = (x1, y1, x2, y2) => {
2818
2817
  }
2819
2818
  return squares.map(pos2key).filter((k) => k !== void 0);
2820
2819
  };
2821
- var adjacentSquares = (square) => {
2822
- const pos = key2pos(square);
2823
- const adjacentSquares2 = [];
2824
- if (pos[0] > 0)
2825
- adjacentSquares2.push([pos[0] - 1, pos[1]]);
2826
- if (pos[0] < 7)
2827
- adjacentSquares2.push([pos[0] + 1, pos[1]]);
2828
- return adjacentSquares2.map(pos2key).filter((k) => k !== void 0);
2829
- };
2830
- var squareShiftedVertically = (square, delta) => {
2831
- const pos = key2pos(square);
2832
- pos[1] += delta;
2833
- return pos2key(pos);
2834
- };
2835
2820
 
2836
2821
  // src/path.ts
2837
2822
  var Path = class _Path {
@@ -3059,8 +3044,12 @@ var PgnViewer = class {
3059
3044
  turnColor: data.turn
3060
3045
  };
3061
3046
  };
3062
- this.analysisUrl = () => this.game.metadata.isLichess && this.game.metadata.externalLink || `https://lichess.org/analysis/${this.curData().fen.replace(" ", "_")}?color=${this.orientation()}`;
3063
- this.practiceUrl = () => `${this.analysisUrl()}#practice`;
3047
+ this.analysisUrl = (forPractice) => {
3048
+ const mainlinePly = this.plyOnMainline();
3049
+ const onMainline = mainlinePly !== void 0;
3050
+ return this.game.metadata.isLichess && this.game.metadata.externalLink && onMainline && !forPractice ? this.game.metadata.externalLink + `#${mainlinePly}` : `https://lichess.org/analysis/${this.curData().fen.replace(" ", "_")}?color=${this.orientation()}`;
3051
+ };
3052
+ this.practiceUrl = () => `${this.analysisUrl(true)}#practice`;
3064
3053
  this.setGround = (cg) => {
3065
3054
  this.ground = cg;
3066
3055
  this.redrawGround();
@@ -3081,108 +3070,24 @@ var PgnViewer = class {
3081
3070
  this.translate = translate(opts.translate);
3082
3071
  this.path = this.game.pathAtMainlinePly(opts.initialPly);
3083
3072
  }
3073
+ plyOnMainline() {
3074
+ const data = this.curData();
3075
+ const ply = isMoveData(data) ? data.ply : 0;
3076
+ const onMainline = ply === 0 ? this.path.empty() : !!this.game.mainline[ply - 1] && this.game.mainline[ply - 1].path.equals(this.path);
3077
+ return onMainline ? ply : void 0;
3078
+ }
3084
3079
  };
3085
3080
 
3086
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/premove.js
3087
- var isDestOccupiedByFriendly = (ctx) => ctx.friendlies.has(ctx.dest.key);
3088
- var isDestOccupiedByEnemy = (ctx) => ctx.enemies.has(ctx.dest.key);
3089
- var anyPieceBetween = (orig, dest, pieces) => squaresBetween(...orig, ...dest).some((s) => pieces.has(s));
3090
- var canEnemyPawnAdvanceToSquare = (pawnStart, dest, ctx) => {
3091
- const piece = ctx.enemies.get(pawnStart);
3092
- if (piece?.role !== "pawn")
3093
- return false;
3094
- const step2 = piece.color === "white" ? 1 : -1;
3095
- const startPos = key2pos(pawnStart);
3096
- const destPos = key2pos(dest);
3097
- return pawnDirAdvance(...startPos, ...destPos, piece.color === "white") && !anyPieceBetween(startPos, [destPos[0], destPos[1] + step2], ctx.allPieces);
3098
- };
3099
- var canEnemyPawnCaptureOnSquare = (pawnStart, dest, ctx) => {
3100
- const enemyPawn = ctx.enemies.get(pawnStart);
3101
- return enemyPawn?.role === "pawn" && pawnDirCapture(...key2pos(pawnStart), ...key2pos(dest), enemyPawn.color === "white") && (ctx.friendlies.has(dest) || canBeCapturedBySomeEnemyEnPassant(squareShiftedVertically(dest, enemyPawn.color === "white" ? -1 : 1), ctx.friendlies, ctx.enemies, ctx.lastMove));
3102
- };
3103
- var canSomeEnemyPawnAdvanceToDest = (ctx) => [...ctx.enemies.keys()].some((key) => canEnemyPawnAdvanceToSquare(key, ctx.dest.key, ctx));
3104
- var isDestControlledByEnemy = (ctx, pieceRolesExclude) => {
3105
- const square = ctx.dest.pos;
3106
- return [...ctx.enemies].some(([key, piece]) => {
3107
- const piecePos = key2pos(key);
3108
- return !pieceRolesExclude?.includes(piece.role) && (piece.role === "pawn" && pawnDirCapture(...piecePos, ...square, piece.color === "white") || piece.role === "knight" && knightDir(...piecePos, ...square) || piece.role === "bishop" && bishopDir(...piecePos, ...square) || piece.role === "rook" && rookDir(...piecePos, ...square) || piece.role === "queen" && queenDir(...piecePos, ...square) || piece.role === "king" && kingDirNonCastling(...piecePos, ...square)) && (!["bishop", "rook", "queen"].includes(piece.role) || !anyPieceBetween(piecePos, square, ctx.allPieces));
3109
- });
3110
- };
3111
- var isFriendlyOnDestAndAttacked = (ctx) => isDestOccupiedByFriendly(ctx) && (canBeCapturedBySomeEnemyEnPassant(ctx.dest.key, ctx.friendlies, ctx.enemies, ctx.lastMove) || isDestControlledByEnemy(ctx));
3112
- var canBeCapturedBySomeEnemyEnPassant = (potentialSquareOfFriendlyPawn, friendlies, enemies, lastMove) => {
3113
- if (!potentialSquareOfFriendlyPawn || lastMove && potentialSquareOfFriendlyPawn !== lastMove[1])
3114
- return false;
3115
- const pos = key2pos(potentialSquareOfFriendlyPawn);
3116
- const friendly = friendlies.get(potentialSquareOfFriendlyPawn);
3117
- return friendly?.role === "pawn" && pos[1] === (friendly.color === "white" ? 3 : 4) && (!lastMove || diff(key2pos(lastMove[0])[1], pos[1]) === 2) && [1, -1].some((delta) => {
3118
- const k = pos2key([pos[0] + delta, pos[1]]);
3119
- return !!k && enemies.get(k)?.role === "pawn";
3120
- });
3121
- };
3122
- var isPathClearEnoughOfFriendliesForPremove = (ctx, isPawnAdvance) => {
3123
- if (ctx.unrestrictedPremoves)
3124
- return true;
3125
- const squaresBetween2 = squaresBetween(...ctx.orig.pos, ...ctx.dest.pos);
3126
- if (isPawnAdvance)
3127
- squaresBetween2.push(ctx.dest.key);
3128
- const squaresOfFriendliesBetween = squaresBetween2.filter((s) => ctx.friendlies.has(s));
3129
- if (!squaresOfFriendliesBetween.length)
3130
- return true;
3131
- const firstSquareOfFriendliesBetween = squaresOfFriendliesBetween[0];
3132
- const nextSquare = squareShiftedVertically(firstSquareOfFriendliesBetween, ctx.color === "white" ? -1 : 1);
3133
- return squaresOfFriendliesBetween.length === 1 && canBeCapturedBySomeEnemyEnPassant(firstSquareOfFriendliesBetween, ctx.friendlies, ctx.enemies, ctx.lastMove) && !!nextSquare && !squaresBetween2.includes(nextSquare);
3134
- };
3135
- var isPathClearEnoughOfEnemiesForPremove = (ctx, isPawnAdvance) => {
3136
- if (ctx.unrestrictedPremoves)
3137
- return true;
3138
- const squaresBetween2 = squaresBetween(...ctx.orig.pos, ...ctx.dest.pos);
3139
- if (isPawnAdvance)
3140
- squaresBetween2.push(ctx.dest.key);
3141
- const squaresOfEnemiesBetween = squaresBetween2.filter((s) => ctx.enemies.has(s));
3142
- if (squaresOfEnemiesBetween.length > 1)
3143
- return false;
3144
- if (!squaresOfEnemiesBetween.length)
3145
- return true;
3146
- const enemySquare = squaresOfEnemiesBetween[0];
3147
- const enemy = ctx.enemies.get(enemySquare);
3148
- if (!enemy || enemy.role !== "pawn")
3149
- return true;
3150
- const enemyStep = enemy.color === "white" ? 1 : -1;
3151
- const squareAbove = squareShiftedVertically(enemySquare, enemyStep);
3152
- const enemyPawnDests = squareAbove ? [
3153
- ...adjacentSquares(squareAbove).filter((s) => canEnemyPawnCaptureOnSquare(enemySquare, s, ctx)),
3154
- ...[squareAbove, squareShiftedVertically(squareAbove, enemyStep)].filter((s) => !!s).filter((s) => canEnemyPawnAdvanceToSquare(enemySquare, s, ctx))
3155
- ] : [];
3156
- const badSquares = [...squaresBetween2, ctx.orig.key];
3157
- return enemyPawnDests.some((square) => !badSquares.includes(square));
3158
- };
3159
- var isPathClearEnoughForPremove = (ctx, isPawnAdvance) => isPathClearEnoughOfFriendliesForPremove(ctx, isPawnAdvance) && isPathClearEnoughOfEnemiesForPremove(ctx, isPawnAdvance);
3160
- var pawn = (ctx) => {
3161
- const step2 = ctx.color === "white" ? 1 : -1;
3162
- if (diff(ctx.orig.pos[0], ctx.dest.pos[0]) > 1)
3163
- return false;
3164
- if (!diff(ctx.orig.pos[0], ctx.dest.pos[0]))
3165
- return pawnDirAdvance(...ctx.orig.pos, ...ctx.dest.pos, ctx.color === "white") && isPathClearEnoughForPremove(ctx, true);
3166
- if (ctx.dest.pos[1] !== ctx.orig.pos[1] + step2)
3167
- return false;
3168
- if (ctx.unrestrictedPremoves || isDestOccupiedByEnemy(ctx))
3169
- return true;
3170
- if (isDestOccupiedByFriendly(ctx))
3171
- return isDestControlledByEnemy(ctx);
3172
- else
3173
- return canSomeEnemyPawnAdvanceToDest(ctx) || canBeCapturedBySomeEnemyEnPassant(pos2key([ctx.dest.pos[0], ctx.dest.pos[1] + step2]), ctx.friendlies, ctx.enemies, ctx.lastMove) || isDestControlledByEnemy(ctx, ["pawn"]);
3174
- };
3175
- var knight = (ctx) => knightDir(...ctx.orig.pos, ...ctx.dest.pos) && (ctx.unrestrictedPremoves || !isDestOccupiedByFriendly(ctx) || isFriendlyOnDestAndAttacked(ctx));
3176
- var bishop = (ctx) => bishopDir(...ctx.orig.pos, ...ctx.dest.pos) && isPathClearEnoughForPremove(ctx, false) && (ctx.unrestrictedPremoves || !isDestOccupiedByFriendly(ctx) || isFriendlyOnDestAndAttacked(ctx));
3177
- var rook = (ctx) => rookDir(...ctx.orig.pos, ...ctx.dest.pos) && isPathClearEnoughForPremove(ctx, false) && (ctx.unrestrictedPremoves || !isDestOccupiedByFriendly(ctx) || isFriendlyOnDestAndAttacked(ctx));
3081
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/premove.js
3082
+ var pawn = (ctx) => diff(ctx.orig.pos[0], ctx.dest.pos[0]) <= 1 && (diff(ctx.orig.pos[0], ctx.dest.pos[0]) === 1 ? ctx.dest.pos[1] === ctx.orig.pos[1] + (ctx.color === "white" ? 1 : -1) : pawnDirAdvance(...ctx.orig.pos, ...ctx.dest.pos, ctx.color === "white"));
3083
+ var knight = (ctx) => knightDir(...ctx.orig.pos, ...ctx.dest.pos);
3084
+ var bishop = (ctx) => bishopDir(...ctx.orig.pos, ...ctx.dest.pos);
3085
+ var rook = (ctx) => rookDir(...ctx.orig.pos, ...ctx.dest.pos);
3178
3086
  var queen = (ctx) => bishop(ctx) || rook(ctx);
3179
- var king = (ctx) => kingDirNonCastling(...ctx.orig.pos, ...ctx.dest.pos) && (ctx.unrestrictedPremoves || !isDestOccupiedByFriendly(ctx) || isFriendlyOnDestAndAttacked(ctx)) || ctx.canCastle && ctx.orig.pos[1] === ctx.dest.pos[1] && ctx.orig.pos[1] === (ctx.color === "white" ? 0 : 7) && (ctx.orig.pos[0] === 4 && (ctx.dest.pos[0] === 2 && ctx.rookFilesFriendlies.includes(0) || ctx.dest.pos[0] === 6 && ctx.rookFilesFriendlies.includes(7)) || ctx.rookFilesFriendlies.includes(ctx.dest.pos[0])) && (ctx.unrestrictedPremoves || /* The following checks if no non-rook friendly piece is in the way between the king and its castling destination.
3180
- Note that for the Chess960 edge case of Kb1 "long castling", the check passes even if there is a piece in the way
3181
- on c1. But this is fine, since premoving from b1 to a1 as a normal move would have already returned true. */
3182
- squaresBetween(...ctx.orig.pos, ctx.dest.pos[0] > ctx.orig.pos[0] ? 7 : 1, ctx.dest.pos[1]).map((s) => ctx.allPieces.get(s)).every((p) => !p || samePiece(p, { role: "rook", color: ctx.color })));
3087
+ var king = (ctx) => kingDirNonCastling(...ctx.orig.pos, ...ctx.dest.pos) || ctx.orig.pos[1] === ctx.dest.pos[1] && ctx.orig.pos[1] === (ctx.color === "white" ? 0 : 7) && (ctx.orig.pos[0] === 4 && (ctx.dest.pos[0] === 2 && ctx.rookFilesFriendlies.includes(0) || ctx.dest.pos[0] === 6 && ctx.rookFilesFriendlies.includes(7)) || ctx.rookFilesFriendlies.includes(ctx.dest.pos[0]));
3183
3088
  var mobilityByRole = { pawn, knight, bishop, rook, queen, king };
3184
3089
  function premove(state, key) {
3185
- const pieces = state.pieces, canCastle = state.premovable.castle, unrestrictedPremoves = !!state.premovable.unrestrictedPremoves;
3090
+ const pieces = state.pieces;
3186
3091
  const piece = pieces.get(key);
3187
3092
  if (!piece || piece.color === state.turnColor)
3188
3093
  return [];
@@ -3192,16 +3097,14 @@ function premove(state, key) {
3192
3097
  allPieces: pieces,
3193
3098
  friendlies,
3194
3099
  enemies,
3195
- unrestrictedPremoves,
3196
3100
  color,
3197
- canCastle,
3198
3101
  rookFilesFriendlies: Array.from(pieces).filter(([k, p]) => k[1] === (color === "white" ? "1" : "8") && p.color === color && p.role === "rook").map(([k]) => key2pos(k)[0]),
3199
3102
  lastMove: state.lastMove
3200
3103
  };
3201
3104
  return allPosAndKey.filter((dest) => mobility({ ...partialCtx, dest })).map((pk) => pk.key);
3202
3105
  }
3203
3106
 
3204
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/board.js
3107
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/board.js
3205
3108
  function callUserFunction(f, ...args) {
3206
3109
  if (f)
3207
3110
  setTimeout(() => f(...args), 1);
@@ -3490,7 +3393,7 @@ function getSnappedKeyAtDomPos(orig, pos, asWhite, bounds) {
3490
3393
  }
3491
3394
  var whitePov = (s) => s.orientation === "white";
3492
3395
 
3493
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/fen.js
3396
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/fen.js
3494
3397
  var initial = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR";
3495
3398
  var roles = {
3496
3399
  p: "pawn",
@@ -3565,7 +3468,7 @@ function write(pieces) {
3565
3468
  }).join("")).join("/").replace(/1{2,}/g, (s) => s.length.toString());
3566
3469
  }
3567
3470
 
3568
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/config.js
3471
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/config.js
3569
3472
  function applyAnimation(state, config) {
3570
3473
  if (config.animation) {
3571
3474
  deepMerge(state.animation, config.animation);
@@ -3616,7 +3519,7 @@ function isPlainObject(o) {
3616
3519
  return proto === Object.prototype || proto === null;
3617
3520
  }
3618
3521
 
3619
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/anim.js
3522
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/anim.js
3620
3523
  var anim = (mutation, state) => state.animation.enabled ? animate(mutation, state) : render(mutation, state);
3621
3524
  function render(mutation, state) {
3622
3525
  const result = mutation(state);
@@ -3707,7 +3610,7 @@ function animate(mutation, state) {
3707
3610
  }
3708
3611
  var easing = (t) => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
3709
3612
 
3710
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/draw.js
3613
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/draw.js
3711
3614
  var brushes = ["green", "red", "blue", "yellow"];
3712
3615
  function start(state, e) {
3713
3616
  if (e.touches && e.touches.length > 1)
@@ -3793,7 +3696,7 @@ function onChange(drawable) {
3793
3696
  drawable.onChange(drawable.shapes);
3794
3697
  }
3795
3698
 
3796
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/drag.js
3699
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/drag.js
3797
3700
  function start2(s, e) {
3798
3701
  if (!(s.trustAllEvents || e.isTrusted))
3799
3702
  return;
@@ -3979,7 +3882,7 @@ function pieceElementByKey(s, key) {
3979
3882
  return;
3980
3883
  }
3981
3884
 
3982
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/explosion.js
3885
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/explosion.js
3983
3886
  function explosion(state, keys) {
3984
3887
  state.exploding = { stage: 1, keys };
3985
3888
  state.dom.redraw();
@@ -3998,7 +3901,7 @@ function setStage(state, stage) {
3998
3901
  }
3999
3902
  }
4000
3903
 
4001
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/api.js
3904
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/api.js
4002
3905
  function start3(state, redrawAll) {
4003
3906
  function toggleOrientation2() {
4004
3907
  toggleOrientation(state);
@@ -4089,7 +3992,7 @@ function start3(state, redrawAll) {
4089
3992
  };
4090
3993
  }
4091
3994
 
4092
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/state.js
3995
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/state.js
4093
3996
  function defaults() {
4094
3997
  return {
4095
3998
  pieces: read(initial),
@@ -4185,7 +4088,7 @@ function defaults() {
4185
4088
  };
4186
4089
  }
4187
4090
 
4188
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/svg.js
4091
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/svg.js
4189
4092
  function createDefs() {
4190
4093
  const defs = createElement("defs");
4191
4094
  const filter = setAttributes(createElement("filter"), { id: "cg-filter-blur" });
@@ -4199,7 +4102,7 @@ function renderSvg(state, els) {
4199
4102
  if (!s.dest)
4200
4103
  continue;
4201
4104
  const sources = dests.get(s.dest) ?? /* @__PURE__ */ new Set(), from = pos2user(orient(key2pos(s.orig), state.orientation), bounds), to = pos2user(orient(key2pos(s.dest), state.orientation), bounds);
4202
- sources.add(moveAngle(from, to));
4105
+ sources.add(angleToSlot(moveAngle(from, to)));
4203
4106
  dests.set(s.dest, sources);
4204
4107
  }
4205
4108
  const shapes = [];
@@ -4210,14 +4113,14 @@ function renderSvg(state, els) {
4210
4113
  shape: s,
4211
4114
  current: false,
4212
4115
  pendingErase: isPendingErase,
4213
- hash: shapeHash(s, isShort(s.dest, dests), false, bounds, isPendingErase)
4116
+ hash: shapeHash(s, isShort(s.dest, dests), false, bounds, isPendingErase, angleCount(s.dest, dests))
4214
4117
  });
4215
4118
  }
4216
4119
  if (cur && pendingEraseIdx === -1)
4217
4120
  shapes.push({
4218
4121
  shape: cur,
4219
4122
  current: true,
4220
- hash: shapeHash(cur, isShort(cur.dest, dests), true, bounds, false),
4123
+ hash: shapeHash(cur, isShort(cur.dest, dests), true, bounds, false, angleCount(cur.dest, dests)),
4221
4124
  pendingErase: false
4222
4125
  });
4223
4126
  const fullHash = shapes.map((sc) => sc.hash).join(";");
@@ -4285,12 +4188,13 @@ function syncShapes(shapes, els, renderShape3) {
4285
4188
  }
4286
4189
  }
4287
4190
  }
4288
- function shapeHash({ orig, dest, brush, piece, modifiers, customSvg, label, below }, shorten, current, bounds, pendingErase) {
4191
+ function shapeHash({ orig, dest, brush, piece, modifiers, customSvg, label, below }, shorten, current, bounds, pendingErase, angleCountOfDest) {
4289
4192
  return [
4290
4193
  bounds.width,
4291
4194
  bounds.height,
4292
4195
  current,
4293
4196
  pendingErase && "pendingErase",
4197
+ angleCountOfDest,
4294
4198
  orig,
4295
4199
  dest,
4296
4200
  brush,
@@ -4302,12 +4206,8 @@ function shapeHash({ orig, dest, brush, piece, modifiers, customSvg, label, belo
4302
4206
  below && "below"
4303
4207
  ].filter((x) => x).join(",");
4304
4208
  }
4305
- function pieceHash(piece) {
4306
- return [piece.color, piece.role, piece.scale].filter((x) => x).join(",");
4307
- }
4308
- function modifiersHash(m) {
4309
- return [m.lineWidth, m.hilite].filter((x) => x).join(",");
4310
- }
4209
+ var pieceHash = (piece) => [piece.color, piece.role, piece.scale].filter((x) => x).join(",");
4210
+ var modifiersHash = (m) => [m.lineWidth, m.hilite].filter((x) => x).join(",");
4311
4211
  function textHash(s) {
4312
4212
  let h2 = 0;
4313
4213
  for (let i = 0; i < s.length; i++) {
@@ -4419,15 +4319,13 @@ function renderLabel(label, hash2, from, to, slots, corner) {
4419
4319
  g.appendChild(labelEl);
4420
4320
  return g;
4421
4321
  }
4422
- function orient(pos, color) {
4423
- return color === "white" ? pos : [7 - pos[0], 7 - pos[1]];
4424
- }
4425
- function isShort(dest, dests) {
4426
- return true === (dest && dests.has(dest) && dests.get(dest).size > 1);
4427
- }
4428
- function createElement(tagName2) {
4429
- return document.createElementNS("http://www.w3.org/2000/svg", tagName2);
4430
- }
4322
+ var orient = (pos, color) => color === "white" ? pos : [7 - pos[0], 7 - pos[1]];
4323
+ var mod = (n, m) => (n % m + m) % m;
4324
+ var rotateAngleSlot = (slot, steps) => mod(slot + steps, 16);
4325
+ var anyTwoCloserThan90Degrees = (slots) => [...slots].some((slot) => [-3, -2, -1, 1, 2, 3].some((i) => slots.has(rotateAngleSlot(slot, i))));
4326
+ var isShort = (dest, dests) => !!dest && dests.has(dest) && anyTwoCloserThan90Degrees(dests.get(dest));
4327
+ var createElement = (tagName2) => document.createElementNS("http://www.w3.org/2000/svg", tagName2);
4328
+ var angleCount = (dest, dests) => dest && dests.has(dest) ? dests.get(dest).size : 0;
4431
4329
  function setAttributes(el, attrs) {
4432
4330
  for (const key in attrs) {
4433
4331
  if (Object.prototype.hasOwnProperty.call(attrs, key))
@@ -4435,30 +4333,20 @@ function setAttributes(el, attrs) {
4435
4333
  }
4436
4334
  return el;
4437
4335
  }
4438
- function makeCustomBrush(base, modifiers) {
4439
- return !modifiers ? base : {
4440
- color: base.color,
4441
- opacity: Math.round(base.opacity * 10) / 10,
4442
- lineWidth: Math.round(modifiers.lineWidth || base.lineWidth),
4443
- key: [base.key, modifiers.lineWidth].filter((x) => x).join("")
4444
- };
4445
- }
4446
- function circleWidth() {
4447
- return [3 / 64, 4 / 64];
4448
- }
4449
- function lineWidth(brush, current) {
4450
- return (brush.lineWidth || 10) * (current ? 0.85 : 1) / 64;
4451
- }
4336
+ var makeCustomBrush = (base, modifiers) => !modifiers ? base : {
4337
+ color: base.color,
4338
+ opacity: Math.round(base.opacity * 10) / 10,
4339
+ lineWidth: Math.round(modifiers.lineWidth || base.lineWidth),
4340
+ key: [base.key, modifiers.lineWidth].filter((x) => x).join("")
4341
+ };
4342
+ var circleWidth = () => [3 / 64, 4 / 64];
4343
+ var lineWidth = (brush, current) => (brush.lineWidth || 10) * (current ? 0.85 : 1) / 64;
4452
4344
  function hiliteOf(shape) {
4453
4345
  const hilite = shape.modifiers?.hilite;
4454
4346
  return { key: hilite && `hilite-${hilite.replace("#", "")}`, color: hilite };
4455
4347
  }
4456
- function opacity(brush, current, pendingErase) {
4457
- return (brush.opacity || 1) * (pendingErase ? 0.6 : current ? 0.9 : 1);
4458
- }
4459
- function arrowMargin(shorten) {
4460
- return (shorten ? 20 : 10) / 64;
4461
- }
4348
+ var opacity = (brush, current, pendingErase) => (brush.opacity || 1) * (pendingErase ? 0.6 : current ? 0.9 : 1);
4349
+ var arrowMargin = (shorten) => (shorten ? 20 : 10) / 64;
4462
4350
  function pos2user(pos, bounds) {
4463
4351
  const xScale = Math.min(1, bounds.width / bounds.height);
4464
4352
  const yScale = Math.min(1, bounds.height / bounds.width);
@@ -4478,31 +4366,25 @@ function filterBox(from, to) {
4478
4366
  stroke: "none"
4479
4367
  });
4480
4368
  }
4481
- function moveAngle(from, to, asSlot = true) {
4482
- const angle = Math.atan2(to[1] - from[1], to[0] - from[0]) + Math.PI;
4483
- return asSlot ? (Math.round(angle * 8 / Math.PI) + 16) % 16 : angle;
4484
- }
4485
- function dist(from, to) {
4486
- return Math.sqrt([from[0] - to[0], from[1] - to[1]].reduce((acc, x) => acc + x * x, 0));
4487
- }
4369
+ var angleToSlot = (angle) => mod(Math.round(angle * 8 / Math.PI), 16);
4370
+ var moveAngle = (from, to) => Math.atan2(to[1] - from[1], to[0] - from[0]) + Math.PI;
4371
+ var dist = (from, to) => Math.sqrt([from[0] - to[0], from[1] - to[1]].reduce((acc, x) => acc + x * x, 0));
4488
4372
  function labelCoords(from, to, slots) {
4489
4373
  let mag = dist(from, to);
4490
- const angle = moveAngle(from, to, false);
4374
+ const angle = moveAngle(from, to);
4491
4375
  if (slots) {
4492
4376
  mag -= 33 / 64;
4493
- if (slots.size > 1) {
4377
+ if (anyTwoCloserThan90Degrees(slots)) {
4494
4378
  mag -= 10 / 64;
4495
- const slot = moveAngle(from, to);
4496
- if (slots.has((slot + 1) % 16) || slots.has((slot + 15) % 16)) {
4497
- if (slot & 1)
4498
- mag -= 0.4;
4499
- }
4379
+ const slot = angleToSlot(angle);
4380
+ if (slot & 1 && [-1, 1].some((s) => slots.has(rotateAngleSlot(slot, s))))
4381
+ mag -= 0.4;
4500
4382
  }
4501
4383
  }
4502
4384
  return [from[0] - Math.cos(angle) * mag, from[1] - Math.sin(angle) * mag].map((c) => c + 0.5);
4503
4385
  }
4504
4386
 
4505
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/wrap.js
4387
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/wrap.js
4506
4388
  function renderWrap(element, s) {
4507
4389
  element.innerHTML = "";
4508
4390
  element.classList.add("cg-wrap");
@@ -4533,10 +4415,10 @@ function renderWrap(element, s) {
4533
4415
  const ranksPositionClass = s.ranksPosition === "left" ? " left" : "";
4534
4416
  if (s.coordinatesOnSquares) {
4535
4417
  const rankN = s.orientation === "white" ? (i) => i + 1 : (i) => 8 - i;
4536
- files.forEach((f, i) => container.appendChild(renderCoords(ranks.map((r) => f + r), "squares rank" + rankN(i) + orientClass + ranksPositionClass)));
4418
+ files.forEach((f, i) => container.appendChild(renderCoords(ranks.map((r) => f + r), "squares rank" + rankN(i) + orientClass + ranksPositionClass, i % 2 === 0 ? "black" : "white")));
4537
4419
  } else {
4538
- container.appendChild(renderCoords(ranks, "ranks" + orientClass + ranksPositionClass));
4539
- container.appendChild(renderCoords(files, "files" + orientClass));
4420
+ container.appendChild(renderCoords(ranks, "ranks" + orientClass + ranksPositionClass, s.ranksPosition === "right" === (s.orientation === "white") ? "white" : "black"));
4421
+ container.appendChild(renderCoords(files, "files" + orientClass, opposite2(s.orientation)));
4540
4422
  }
4541
4423
  }
4542
4424
  let ghost;
@@ -4558,18 +4440,19 @@ function svgContainer(cls, isShapes) {
4558
4440
  svg.appendChild(createElement("g"));
4559
4441
  return svg;
4560
4442
  }
4561
- function renderCoords(elems, className) {
4443
+ function renderCoords(elems, className, firstColor) {
4562
4444
  const el = createEl("coords", className);
4563
4445
  let f;
4564
- for (const elem of elems) {
4565
- f = createEl("coord");
4446
+ elems.forEach((elem, i) => {
4447
+ const light = i % 2 === (firstColor === "white" ? 0 : 1);
4448
+ f = createEl("coord", `coord-${light ? "light" : "dark"}`);
4566
4449
  f.textContent = elem;
4567
4450
  el.appendChild(f);
4568
- }
4451
+ });
4569
4452
  return el;
4570
4453
  }
4571
4454
 
4572
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/drop.js
4455
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/drop.js
4573
4456
  function drop(s, e) {
4574
4457
  if (!s.dropmode.active)
4575
4458
  return;
@@ -4586,7 +4469,7 @@ function drop(s, e) {
4586
4469
  s.dom.redraw();
4587
4470
  }
4588
4471
 
4589
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/events.js
4472
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/events.js
4590
4473
  function bindBoard(s, onResize) {
4591
4474
  const boardEl = s.dom.elements.board;
4592
4475
  if ("ResizeObserver" in window)
@@ -4648,10 +4531,10 @@ var dragOrDraw = (s, withDrag, withDraw) => (e) => {
4648
4531
  withDrag(s, e);
4649
4532
  };
4650
4533
 
4651
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/render.js
4534
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/render.js
4652
4535
  function render2(s) {
4653
- const asWhite = whitePov(s), posToTranslate2 = posToTranslate(s.dom.bounds()), boardEl = s.dom.elements.board, pieces = s.pieces, curAnim = s.animation.current, anims = curAnim ? curAnim.plan.anims : /* @__PURE__ */ new Map(), fadings = curAnim ? curAnim.plan.fadings : /* @__PURE__ */ new Map(), curDrag = s.draggable.current, squares = computeSquareClasses(s), samePieces = /* @__PURE__ */ new Set(), sameSquares = /* @__PURE__ */ new Set(), movedPieces = /* @__PURE__ */ new Map(), movedSquares = /* @__PURE__ */ new Map();
4654
- let k, el, pieceAtKey, elPieceName, anim2, fading, pMvdset, pMvd, sMvdset, sMvd;
4536
+ const asWhite = whitePov(s), posToTranslate2 = posToTranslate(s.dom.bounds()), boardEl = s.dom.elements.board, pieces = s.pieces, curAnim = s.animation.current, anims = curAnim ? curAnim.plan.anims : /* @__PURE__ */ new Map(), fadings = curAnim ? curAnim.plan.fadings : /* @__PURE__ */ new Map(), curDrag = s.draggable.current, samePieces = /* @__PURE__ */ new Set(), movedPieces = /* @__PURE__ */ new Map(), desiredSquares = computeSquareClasses(s), availableSquares = /* @__PURE__ */ new Map();
4537
+ let k, el, pieceAtKey, elPieceName, anim2, fading, pMvdset, pMvd, sAvail;
4655
4538
  el = boardEl.firstChild;
4656
4539
  while (el) {
4657
4540
  k = el.cgKey;
@@ -4683,44 +4566,43 @@ function render2(s) {
4683
4566
  if (s.addPieceZIndex)
4684
4567
  el.style.zIndex = posZIndex(key2pos(k), asWhite);
4685
4568
  }
4686
- if (elPieceName === pieceNameOf(pieceAtKey) && (!fading || !el.cgFading)) {
4569
+ if (elPieceName === pieceNameOf(pieceAtKey) && (!fading || !el.cgFading))
4687
4570
  samePieces.add(k);
4688
- } else {
4689
- if (fading && elPieceName === pieceNameOf(fading)) {
4690
- el.classList.add("fading");
4691
- el.cgFading = true;
4692
- } else {
4693
- appendValue(movedPieces, elPieceName, el);
4694
- }
4695
- }
4696
- } else {
4571
+ else if (fading && elPieceName === pieceNameOf(fading)) {
4572
+ el.classList.add("fading");
4573
+ el.cgFading = true;
4574
+ } else
4575
+ appendValue(movedPieces, elPieceName, el);
4576
+ } else
4697
4577
  appendValue(movedPieces, elPieceName, el);
4698
- }
4699
4578
  } else if (isSquareNode(el)) {
4700
- const cn = el.className;
4701
- if (squares.get(k) === cn)
4702
- sameSquares.add(k);
4703
- else
4704
- appendValue(movedSquares, cn, el);
4579
+ const cls = el.className;
4580
+ if (desiredSquares.get(k) === cls) {
4581
+ setVisible(el, true);
4582
+ desiredSquares.delete(k);
4583
+ } else
4584
+ appendValue(availableSquares, cls, el);
4705
4585
  }
4706
4586
  el = el.nextSibling;
4707
4587
  }
4708
- for (const [sk, className] of squares) {
4709
- if (!sameSquares.has(sk)) {
4710
- sMvdset = movedSquares.get(className);
4711
- sMvd = sMvdset && sMvdset.pop();
4712
- const translation = posToTranslate2(key2pos(sk), asWhite);
4713
- if (sMvd) {
4714
- sMvd.cgKey = sk;
4715
- translate2(sMvd, translation);
4716
- } else {
4717
- const squareNode = createEl("square", className);
4718
- squareNode.cgKey = sk;
4719
- translate2(squareNode, translation);
4720
- boardEl.insertBefore(squareNode, boardEl.firstChild);
4721
- }
4588
+ for (const [sk, className] of desiredSquares) {
4589
+ sAvail = availableSquares.get(className)?.pop();
4590
+ const translation = posToTranslate2(key2pos(sk), asWhite);
4591
+ if (sAvail) {
4592
+ sAvail.cgKey = sk;
4593
+ translate2(sAvail, translation);
4594
+ setVisible(sAvail, true);
4595
+ } else {
4596
+ const squareNode = createEl("square", className);
4597
+ squareNode.cgKey = sk;
4598
+ translate2(squareNode, translation);
4599
+ boardEl.insertBefore(squareNode, boardEl.firstChild);
4722
4600
  }
4723
4601
  }
4602
+ for (const [_, nodes] of availableSquares.entries()) {
4603
+ for (const node of nodes)
4604
+ setVisible(node, false);
4605
+ }
4724
4606
  for (const [k2, p] of pieces) {
4725
4607
  anim2 = anims.get(k2);
4726
4608
  if (!samePieces.has(k2)) {
@@ -4760,8 +4642,6 @@ function render2(s) {
4760
4642
  }
4761
4643
  for (const nodes of movedPieces.values())
4762
4644
  removeNodes(s, nodes);
4763
- for (const nodes of movedSquares.values())
4764
- removeNodes(s, nodes);
4765
4645
  }
4766
4646
  function renderResized(s) {
4767
4647
  const asWhite = whitePov(s), posToTranslate2 = posToTranslate(s.dom.bounds());
@@ -4798,27 +4678,21 @@ function posZIndex(pos, asWhite) {
4798
4678
  return `${z}`;
4799
4679
  }
4800
4680
  var pieceNameOf = (piece) => `${piece.color} ${piece.role}`;
4681
+ var normalizeLastMoveStandardRookCastle = (s, k) => !!s.lastMove?.[1] && !s.pieces.has(s.lastMove[1]) && s.lastMove[0][0] === "e" && ["h", "a"].includes(s.lastMove[1][0]) && s.lastMove[0][1] === s.lastMove[1][1] && squaresBetween(...key2pos(s.lastMove[0]), ...key2pos(s.lastMove[1])).some((sq) => s.pieces.has(sq)) ? (k > s.lastMove[0] ? "g" : "c") + k[1] : k;
4801
4682
  function computeSquareClasses(s) {
4802
4683
  const squares = /* @__PURE__ */ new Map();
4803
4684
  if (s.lastMove && s.highlight.lastMove)
4804
- for (const k of s.lastMove) {
4805
- addSquare(squares, k, "last-move");
4806
- }
4685
+ for (const [i, k] of s.lastMove.entries())
4686
+ addSquare(squares, i === 1 ? normalizeLastMoveStandardRookCastle(s, k) : k, "last-move");
4807
4687
  if (s.check && s.highlight.check)
4808
4688
  addSquare(squares, s.check, "check");
4809
4689
  if (s.selected) {
4810
4690
  addSquare(squares, s.selected, "selected");
4811
4691
  if (s.movable.showDests) {
4812
- const dests = s.movable.dests?.get(s.selected);
4813
- if (dests)
4814
- for (const k of dests) {
4815
- addSquare(squares, k, "move-dest" + (s.pieces.has(k) ? " oc" : ""));
4816
- }
4817
- const pDests = s.premovable.customDests?.get(s.selected) ?? s.premovable.dests;
4818
- if (pDests)
4819
- for (const k of pDests) {
4820
- addSquare(squares, k, "premove-dest" + (s.pieces.has(k) ? " oc" : ""));
4821
- }
4692
+ for (const k of s.movable.dests?.get(s.selected) ?? [])
4693
+ addSquare(squares, k, "move-dest" + (s.pieces.has(k) ? " oc" : ""));
4694
+ for (const k of s.premovable.customDests?.get(s.selected) ?? s.premovable.dests ?? [])
4695
+ addSquare(squares, k, "premove-dest" + (s.pieces.has(k) ? " oc" : ""));
4822
4696
  }
4823
4697
  }
4824
4698
  const premove2 = s.premovable.current;
@@ -4853,7 +4727,7 @@ function appendValue(map, key, value) {
4853
4727
  map.set(key, [value]);
4854
4728
  }
4855
4729
 
4856
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/sync.js
4730
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/sync.js
4857
4731
  function syncShapes2(shapes, root, renderShape3) {
4858
4732
  const hashesInDom = /* @__PURE__ */ new Map(), toRemove = [];
4859
4733
  for (const sc of shapes)
@@ -4875,7 +4749,7 @@ function syncShapes2(shapes, root, renderShape3) {
4875
4749
  }
4876
4750
  }
4877
4751
 
4878
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/autoPieces.js
4752
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/autoPieces.js
4879
4753
  function render3(state, autoPieceEl) {
4880
4754
  const autoPieces = state.drawable.autoShapes.filter((autoShape) => autoShape.piece);
4881
4755
  const autoPieceShapes = autoPieces.map((s) => {
@@ -4910,7 +4784,7 @@ function renderShape2(state, { shape, hash: hash2 }, bounds) {
4910
4784
  }
4911
4785
  var hash = (autoPiece) => [autoPiece.orig, autoPiece.piece?.role, autoPiece.piece?.color, autoPiece.piece?.scale].join(",");
4912
4786
 
4913
- // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/chessground.js
4787
+ // node_modules/.pnpm/@lichess-org+chessground@10.0.1/node_modules/@lichess-org/chessground/dist/chessground.js
4914
4788
  function Chessground(element, config) {
4915
4789
  const maybeState = defaults();
4916
4790
  configure(maybeState, config || {});
@@ -5785,7 +5659,7 @@ var renderMenu = (ctrl) => h(
5785
5659
  {
5786
5660
  attrs: {
5787
5661
  role: "menuitem",
5788
- href: ctrl.analysisUrl(),
5662
+ href: ctrl.analysisUrl(false),
5789
5663
  target: "_blank",
5790
5664
  "aria-label": ctrl.translate("aria.linkOpensInNewTab", ctrl.translate("analysisBoard"))
5791
5665
  }
@@ -5815,7 +5689,7 @@ var renderMenu = (ctrl) => h(
5815
5689
  },
5816
5690
  ctrl.translate("getPgn")
5817
5691
  ) : void 0,
5818
- renderExternalLink(ctrl)
5692
+ !ctrl.game.metadata.isLichess || !ctrl.opts.menu.analysisBoard?.enabled ? renderExternalLink(ctrl) : void 0
5819
5693
  ]
5820
5694
  );
5821
5695
  var renderExternalLink = (ctrl) => {