Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions shell/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ type RenderTemplateData struct {
PlayerOnTurn int // 0 or 1 - which player is on turn
LastPlay string // Last play summary
AlphabetScores template.JS // JSON map of letter → score for the current alphabet
BoardLayout template.JS // JSON array of strings, one per row, using bonus square symbols
BoardDimension int // Board size (15 for standard, 21 for super)
}

type Response struct {
Expand Down Expand Up @@ -1429,6 +1431,21 @@ func (sc *ShellController) render3D(cmd *shellcmd) (*Response, error) {
alphabetScoresJSON = []byte("{}")
}

// Build board layout from the actual game board bonuses
dim := board.Dim()
layoutRows := make([]string, dim)
for row := 0; row < dim; row++ {
rowBytes := make([]byte, dim)
for col := 0; col < dim; col++ {
rowBytes[col] = byte(board.GetBonus(row, col))
}
layoutRows[row] = string(rowBytes)
}
boardLayoutJSON, err := json.Marshal(layoutRows)
if err != nil {
boardLayoutJSON = []byte("[]")
}

// Prepare template data
data := RenderTemplateData{
FEN: fen,
Expand All @@ -1447,6 +1464,8 @@ func (sc *ShellController) render3D(cmd *shellcmd) (*Response, error) {
PlayerOnTurn: sc.game.PlayerOnTurn(),
LastPlay: lastPlay,
AlphabetScores: template.JS(alphabetScoresJSON),
BoardLayout: template.JS(boardLayoutJSON),
BoardDimension: dim,
}

// Parse and execute template
Expand Down
50 changes: 17 additions & 33 deletions shell/render_template.html
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,11 @@
const labelColor = getLabelColor(boardColorHex);

// Constants from jade
const gridSize = 15;
const squareSize = 5;
const gridSize = {{.BoardDimension}};
const squareSize = 5 * 15 / gridSize; // Scale so total board footprint is always 75 units
const boardThickness = 2;
const gridHeight = 1;
const tileDepth = 1.5;
const tileDepth = 1.5 * 15 / gridSize;
const offset = (gridSize * squareSize) / 2 - squareSize / 2;
const boardTileZPos = boardThickness / 2 + gridHeight;

Expand All @@ -143,24 +143,8 @@
const rackDepth = 7;
const rackYPos = -38;

// Bonus square layout (Scrabble standard)
const gridLayout = [
"= ' = ' =",
' - " " - ',
" - ' ' - ",
"' - ' - '",
" - - ",
' " " " " ',
" ' ' ' ' ",
"= ' - ' =",
" ' ' ' ' ",
' " " " " ',
" - - ",
"' - ' - '",
" - ' ' - ",
' - " " - ',
"= ' = ' ="
];
// Bonus square layout (from game board)
const gridLayout = {{.BoardLayout}};

const bonusColors = {
'=': 0xcc5555, // Triple word (desaturated red)
Expand Down Expand Up @@ -384,7 +368,7 @@
if (score > 0) {
const scoreGeometry = new TextGeometry(score.toString(), {
font: font,
size: 1,
size: squareSize * 0.2,
height: 0.1 // Some versions use 'height' instead of 'depth'
});
const scoreMesh = new THREE.Mesh(scoreGeometry, letterMaterial);
Expand Down Expand Up @@ -635,7 +619,7 @@
// Grid configuration
const tilesPerRow = 5;
const tileSpacing = squareSize + 0.5;
const startX = offset + squareSize * 4.25; // Shift 2.25 tile widths to the right
const startX = 55 + squareSize * 0.25; // Start just outside the circular board base (radius 55)
const startY = offset; // Start from top
const tableTopZ = -boardThickness / 2; // Table surface height

Expand Down Expand Up @@ -707,8 +691,8 @@
scene.add(base);

const gridBottomZPos = boardThickness / 2;
const wallThickness = 0.25;
const wallHeight = 0.55;
const wallThickness = squareSize * 0.05;
const wallHeight = squareSize * 0.11;

// Create grid squares
for (let i = 0; i < gridSize; i++) {
Expand Down Expand Up @@ -782,7 +766,7 @@
const labelText = bonusLabels[bonusType];
const labelGeom = new TextGeometry(labelText, {
font: font,
size: 1.4,
size: squareSize * 0.28,
height: 0.02, // Some versions use 'height' instead of 'depth'
curveSegments: 4,
bevelEnabled: false
Expand All @@ -805,12 +789,12 @@
}
}

// Add column labels (A-O)
const columns = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'];
// Add column labels (A through the board dimension)
const columns = Array.from({ length: gridSize }, (_, i) => String.fromCharCode(65 + i));
columns.forEach((letter, index) => {
const geometry = new TextGeometry(letter, {
font: font,
size: 1.875,
size: squareSize * 0.375,
height: 0.05, // Some versions use 'height' instead of 'depth'
curveSegments: 8,
bevelEnabled: false
Expand All @@ -826,21 +810,21 @@
});

// Add row labels (1-15)
for (let i = 0; i < 15; i++) {
for (let i = 0; i < gridSize; i++) {
const number = (i + 1).toString();
const geometry = new TextGeometry(number, {
font: font,
size: 1.875,
size: squareSize * 0.375,
height: 0.05, // Some versions use 'height' instead of 'depth'
curveSegments: 8,
bevelEnabled: false
});
const material = new THREE.MeshBasicMaterial({ color: labelColor });
const mesh = new THREE.Mesh(geometry, material);
const textWidth = number.length * 1.5;
const textWidth = number.length * squareSize * 0.3;
mesh.position.set(
-offset - squareSize * 0.65 - textWidth,
(14 - i) * squareSize - offset - squareSize / 4,
(gridSize - 1 - i) * squareSize - offset - squareSize / 4,
boardThickness / 2 + 0.01
);
scene.add(mesh);
Expand Down