Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Chess Bundle Laravel Package

p-chess/chess-bundle

A Symfony bundle for chess applications, providing integration with the p-chess library for board state, legal move validation, FEN/PGN handling, and game management. Add chess logic to your Symfony services and controllers without building the rules engine from scratch.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install the engine, not the bundle. composer require p-chess/chess gives you the rules engine (boards, pieces, moves, FEN/PGN). p-chess/chess-bundle is a Symfony bundle: it ships a Bundle class, DI extension, and Twig extensions/templates. Laravel has no use for any of that, and package discovery will not find it — do not expect a service provider to register itself.
  • Look first at vendor/p-chess/chess/src. The engine namespace is PChess\Chess (Chess, Board, Piece, Move). Read the class you will call most — the Chess facade — before the bundle's Twig layer. The bundle is worth reading only as a reference implementation: its templates show how the maintainers render a board, which is a good starting point for a Blade component.
  • Wire one binding. A thin ChessService in app/Services resolved from the container, so controllers, jobs, and tests share one entry point rather than instantiating the engine in five places:
// app/Providers/AppServiceProvider.php
$this->app->singleton(ChessService::class, fn () => new ChessService());
// app/Services/ChessService.php
namespace App\Services;

use PChess\Chess\Chess;

class ChessService
{
    public function fromFen(string $fen): Chess
    {
        return Chess::create()->load($fen);
    }

    public function legalMoves(string $fen): array
    {
        return $this->fromFen($fen)->moves(); // verify return shape in vendor source
    }
}
  • First use case: a POST /games/{game}/moves endpoint that takes a game's stored FEN plus a SAN/UCI move, loads the position, rejects illegal moves, applies the move, and persists the resulting FEN. That single round trip exercises the whole engine surface you will actually use day to day and is the fastest way to learn the API.
  • Do not spend your first day on rendering. Board markup is the part you will write yourself in Blade and the part with the least framework value contributed by the bundle. Get the rules path correct first; add a <x-chess-board :fen="..." /> component once FEN round-tripping is trustworthy.

Implementation Patterns

  • Treat FEN as the persistence format. Store the position as a single fen string column on your games table, not as serialized piece rows. Every load is Chess::create()->load($game->fen), every save is ->fen(). This keeps your schema stable if you swap engines and makes debug snapshots trivial to paste into any chess tool.
  • Keep a move history table alongside it. A moves table (game_id, ply, san, uci, fen_after, created_at) gives you replay, undo, and an audit trail for free. Undo becomes "load fen_after from ply N-1" rather than an engine feature you have to trust.
  • Validate with a FormRequest + custom Rule, not in the controller. A LegalChessMove rule that loads the game's FEN and checks the submitted move against legal moves keeps the controller thin and makes the rule unit-testable without HTTP. This is the single biggest ergonomics win in a Laravel codebase.
  • Expose legal moves as a small JSON endpoint for the frontend. GET /games/{game}/moves returning { from, to, san, promotion } per candidate lets you build click-to-move boards and highlight overlays in Alpine or Livewire without shipping the rules engine to the browser. Cache this response per FEN (see below).
  • Build a Blade component for the board and keep it dumb. The component receives a FEN (and optionally an array of legal-move targets) and renders 64 squares plus piece glyphs. All chess decisions happen server-side; the component does zero legality logic. This mirrors the bundle's separation of engine and Twig templates, just in Blade:
{{-- resources/views/components/chess-board.blade.php --}}
<div class="chess-board" data-fen="{{ $fen }}" role="img" aria-label="Chess position">
    @foreach ($this->squares() as $square)
        <div class="chess-square {{ $square['class'] }}">
            @if ($square['piece'])
                <x-chess-piece :piece="$square['piece']" />
            @endif
        </div>
    @endforeach
</div>
  • Size squares in CSS, not in PHP. Set the board to a CSS grid with --square-size (or aspect-ratio: 1 and percentages) and make piece SVGs width: 100%; height: 100%. This is exactly what v1.5.0 addresses upstream — if you copy the bundle's approach, copy the CSS-variable pattern rather than fixed pixel dimensions.
  • Use Livewire or Inertia for interactivity, with the server as the referee. In Livewire, post the attempted move, let the service validate/apply, then re-render with the new FEN. In Inertia/Vue, the same but the FEN comes back in the props. Never let the client mutate board state directly; you will end up with two sources of truth and illegal positions in your database.
  • Cache legal-move lists per FEN. Positions repeat (openings, undo, analysis re-runs). Cache::remember("chess:moves:".md5($fen), $ttl, fn () => $this->legalMoves($fen)) is a one-line win and safe because the output is a pure function of the FEN.
  • Push any search/analysis off the request. Move generation for one ply is fast and fine inline. Anything that looks ahead (best move, evaluation, PGN batch import of thousands of games) belongs in a queued job. A web request that runs the engine for seconds is a request that times out under load.
  • For PGN import, wrap each game in a transaction. Parse, replay move by move through the engine to validate, then insert the game plus its moves. A single malformed game should fail its own row, not abort the batch — collect errors and report them.
  • Test with a golden-file corpus. Keep a tests/Fixtures/positions/ directory of FEN → expected legal-move sets, plus a handful of PGN games with known results. Assert against that corpus after every engine bump. This is the highest-value test suite for this dependency, well above anything you would write about rendering.
  • Pin the engine, ignore the bundle. "p-chess/chess": "^1.5" in composer.json. Record the bundle's version and PR link in a comment or ADR for reference, but keep it out of require.

Gotchas and Tips

  • The bundle will not "just work" in Laravel, and you should not try to make it. It expects Symfony's bundle registration, DI extension, and Twig environment. Pulling in symfony/twig-bundle and a config/bundles.php shim to render a chessboard is a losing trade. Consume the engine directly.
  • Verify method names against vendor/ before trusting a tutorial. Small packages like this have thin docs; the source is the contract. moves(), load(), fen(), move() are the shape, but check return types and exception behaviour in the installed version rather than assuming from the README.
  • v1.5.0 is cosmetic. The only change is "scale board pieces with the square" (PR #11). If you are not using the bundle's Twig templates, this release is a no-op for you. Do not schedule it; do not write a migration for it.
  • If you do port the bundle templates or CSS, the sizing fix breaks silently. Fixed width/height rules in your app CSS, flex/grid constraints, or an SVG without a proper viewBox/preserveAspectRatio will all defeat square-based scaling. When pieces look wrong at non-default board sizes: inspect computed square size vs. piece size first, then the SVG attributes, then your own overrides.
  • Clear caches after any template/asset change. php artisan view:clear && php artisan cache:clear and rebuild front-end assets. Stale compiled Blade views and stale public/build hashes are the usual culprits for "I changed it but nothing happened."
  • Never edit vendor/p-chess/chess. If you need custom rules (variant chess, custom starting positions), extend or wrap the engine classes in app/, or fork-and-vendor with a documented upstream diff. Vendor edits vanish on the next composer update and are invisible in code review.
  • Check the engine's composer.json PHP constraint before upgrading. The changelog does not state PHP/Symfony floors. If your runtime is on an older PHP minor, a routine composer update can fail or, worse, resolve to an older engine tag without telling you. Commit the lock file.
  • Watch the bus factor. A single contributor appears on recent releases. The engine is small and deterministic, which makes it a reasonable dependency, but plan for upstream going quiet: the fork path is realistic, and the golden-file test corpus is what makes that fork cheap.
  • FEN is not enough for variants. If you ever add Chess960 or custom start positions, the plain FEN column plus standard rules engine is a dead end. Note that now, before the schema is in production, so you know whether a variant column is needed later.
  • Distinguish glyph vs. SVG rendering early. Unicode chess glyphs are zero-effort but render inconsistently across fonts and platforms and are painful to theme. SVG piece sets are more work up front and almost always the right call — pick one deliberately rather than drifting from the other.
  • Escape FEN output in HTML. A FEN is user-supplied when players can set up positions; it lands in data-fen attributes and debug panels. Blade's {{ }} protects you; {!! !!} does not.
  • Board rendering is stateless and cacheable. If board HTML is expensive at scale, cache per FEN with a short TTL. There is no session, no external I/O, and no per-user state in the engine — horizontal scaling is a non-issue, so do not over-engineer it.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator