Talishar is a browser-based platform to play Flesh and Blood. It is a fan-made FABTCG project not associated with Legend Story Studios.
Visit Talishar.net to get playing Flesh & Blood in your browser right now!
This is the front end client for talishar.net - completely separate from the back end.
This is a Vite single page React App using Redux, Redux Toolkit, and React Redux bindings.
- Volta or FNM to manage node installs.
- node.js (currently 16.19.0), which would be managed automagically by Volta for you.
- git
- basic knowledge of the command line / terminal
- If you're on Windows, get Windows Powershell or wsl or something.
git clone https://github.com/Talishar/Talishar-FE
cd Talishar-FE
npm install
npm run dev
Access the server at http://localhost:5173/ (Port 5173 by default, if you configure it to something else in Vite then it'll be there instead).
You must have the Talishar backend running locally to develop. The backend runs on localhost:8000 (via Docker)
You will also need the local dev talishar backend running.
If you have problems running the development server, come to the discord and ask for help.
Talishar-FE uses Redux Toolkit for centralized state management. The game state flows from the backend through Redux to React components.
src/redux/GameSlice.ts- Redux slice managing the game state (actions, reducers, selectors)src/redux/hooks.ts- Custom hooks for accessing Redux (useAppSelector,useAppDispatch)src/features/api/apiSlice.ts- Redux-based API integration (fetch backend data)ParseGameState.ts- Transforms backend JSON response to Redux-compatible format
Backend (GetNextTurn.php)
↓ (JSON response)
Frontend API call
↓ (response data)
ParseGameState.ts (transforms data)
↓ (normalized format)
GameSlice reducers (updates Redux)
↓ (state changes)
Components (subscribe via selectors)
↓ (re-render with new data)
UI updates
Access game state:
import { useAppSelector } from '@/redux/hooks';
import { selectGameState, selectCurrentPlayer } from '@/redux/slices/GameSlice';
export const MyComponent = () => {
const gameState = useAppSelector(selectGameState);
const currentPlayer = useAppSelector(selectCurrentPlayer);
return <div>{/* Use gameState and currentPlayer */}</div>;
};Dispatch game actions:
import { useAppDispatch } from '@/redux/hooks';
import { updateGameState } from '@/redux/slices/GameSlice';
export const MyComponent = () => {
const dispatch = useAppDispatch();
const handleAction = () => {
dispatch(updateGameState(newState));
};
return <button onClick={handleAction}>Take Action</button>;
};src/routes/game/components/
├── GameBoard/ # Main game board display
├── Hand/ # Player's hand zone
├── PlayArea/ # Cards in play
├── ActionPrompts/ # User interaction prompts
├── Chat/ # Game chat
├── PlayerStats/ # Player health, resources
└── ...other features
Components connect to game state through Redux selectors:
-
Container Components (smart components)
- Use
useAppSelectorto access Redux state - Use
useAppDispatchto trigger actions - Located at feature level (e.g.,
GameBoard/GameBoard.tsx)
- Use
-
Presentational Components (dumb components)
- Receive data via props
- Don't directly access Redux
- Reusable across different contexts
Example:
// Container component (smart)
export const GameBoard = () => {
const gameState = useAppSelector(selectGameState);
const dispatch = useAppDispatch();
const handlePlayCard = (cardId: string) => {
dispatch(playCard(cardId));
};
return <GameBoardView state={gameState} onPlayCard={handlePlayCard} />;
};
// Presentational component (dumb)
export const GameBoardView = ({ state, onPlayCard }: Props) => {
return (
<div>
{state.cards.map(card => (
<Card key={card.id} onClick={() => onPlayCard(card.id)} />
))}
</div>
);
};If you run into any trouble setting up the project please let LaustinSpayce know so we can fix it, and help make it a smoother process for future contributors.
If you have any configuration that isn't the default for the backend, change the hostname, ports etc in the .env file. You can also twiddle with the .env if you want to develop the FE locally but hook up into the production backend (then you'll want to point to api.talishar.net)
Configure Prettier and ESLint in your text editor of choice for a better development experience.
The codebase is organized with small, focused React components and containers. If you have ideas for better organization, please share them. When contributing:
- Keep everything as modular as possible
- Use React containers for logic separation
- Pull data from Redux where appropriate
- Use CSS modules to keep styles locally scoped
- Automatic deployment to CDN
- Automatic testing for all merge requests and commits to main
This project was originally bootstrapped with Create React App, and is now using Vite.
To learn React, check out the React documentation.
There is some redux stuff involved here too so check the React Redux documentation too.
All artwork and card images © Legend Story Studios.
Talishar.net is in no way affiliated with Legend Story Studios. Legend Story Studios®, Flesh and Blood™, and set names are trademarks of Legend Story Studios. Flesh and Blood characters, cards, logos, and art are property of Legend Story Studios.
