Expert in maintaining and extending an Astro 5 static site with Bootstrap, TypeScript game logic, and ML training integration.
This skill has been flagged as potentially dangerous. It contains patterns that could compromise your security or manipulate AI behavior.Safety score: 20/100.
KillerSkills scans all public content for safety. Use caution before installing or executing flagged content.
Expert guidance for working with the wemee.github.io codebase - an Astro 5 static site featuring interactive games, math visualizations, and ML-powered AI agents.
This project uses a **three-layer architecture** for game development with RL training support:
1. **GameCore Layer**: Pure TypeScript logic (no DOM/Canvas), Gymnasium-compatible interface
2. **Game Layer**: Browser rendering and user input handling
3. **AI Agent Layer**: TensorFlow.js models trained via Python RL and loaded in browser
```bash
npm run dev # Dev server at localhost:4321
npm run dev -- --host # LAN access for mobile testing
npm run build # Build static site to dist/
npm run preview # Preview production build
npm run build:{game}-core # Build GameCore for Python training
```
1. Create `.astro` file in appropriate `src/pages/` subdirectory
2. Wrap content with `<BaseLayout title="..." description="...">` for SEO
3. **Manually update** `src/components/Navbar.astro` to add navigation link
4. Update relevant index page (`game/index.astro`, `math/index.astro`, etc.)
1. Create TypeScript class in `src/lib/games/` or `src/lib/math/`
2. Use shared types from `src/lib/games/types.ts` when applicable
3. Import and instantiate in page's `<script>` block with `document.addEventListener('DOMContentLoaded', ...)`
4. Follow canvas class pattern:
- Constructor takes `canvasId` and optional callbacks
- Handle `devicePixelRatio` for Retina displays
- Use `requestAnimationFrame` for game loops
- Provide `destroy()` method for cleanup
**Step 1: Frontend (TypeScript)**
Create GameCore (`src/lib/games/{Game}Core.ts`):
```typescript
import { GameCore, type StepResult } from './core/GameCore';
export interface GameState {
// Define state properties
}
export type Action = 'left' | 'right' | ...;
export class MyGameCore extends GameCore<GameState, Action> {
reset(): GameState { /* Initialize */ }
step(action: Action): StepResult<GameState> {
// Return {observation, reward, terminated, truncated, info}
}
getState(): GameState { /* Current state */ }
}
```
Refactor Game class to use Core:
```typescript
export class MyGame {
private core: MyGameCore;
constructor() {
this.core = new MyGameCore({ /* config */ });
}
private update() {
const action = this.getUserInput();
const result = this.core.step(action);
this.render(result.observation);
}
}
```
Create AI Agent (`src/lib/ai/agents/{Game}WeightsAgent.ts`):
```typescript
export class MyGameWeightsAgent extends TFJSAgent<GameState, Action> {
protected observationToTensor(state: GameState): any {
// Convert state to model input
}
protected async tensorToAction(tensor: any): Promise<PredictionResult<Action>> {
// Convert output to action
}
}
```
Add build script to `package.json`:
```json
{
"scripts": {
"build:mygame-core": "esbuild src/lib/games/MyGameCore.ts --bundle --format=iife --global-name=MyGameCore --outfile=ml-training/mygame-rl/dist/MyGameCore.js"
}
}
```
**Step 2: Training (Python)**
Create `ml-training/mygame-rl/` directory with:
1. **Gymnasium Environment** (`mygame_env.py`):
```python
import gymnasium as gym
from py_mini_racer import MiniRacer
import numpy as np
class MyGameEnv(gym.Env):
def __init__(self):
self.ctx = MiniRacer()
code = open('dist/MyGameCore.js').read()
self.ctx.eval(code)
self.ctx.eval("const game = new MyGameCore.MyGameCore();")
self.action_space = spaces.Discrete(N)
self.observation_space = spaces.Box(...)
def reset(self, seed=None, options=None):
state_json = self.ctx.eval("JSON.stringify(game.reset())")
return self._get_obs(json.loads(state_json)), {}
def step(self, action):
result_json = self.ctx.eval(f"JSON.stringify(game.step(...))")
result = json.loads(result_json)
return (self._get_obs(result['observation']),
result['reward'],
result['terminated'],
result['truncated'],
result.get('info', {}))
```
2. **Training Script** (`train.py`):
```python
from shared.base_trainer import BaseRLTrainer
from stable_baselines3 import PPO
class MyGameRLTrainer(BaseRLTrainer):
def create_model(self, env):
return PPO("MlpPolicy", env, ...)
trainer = MyGameRLTrainer(env_id='MyGame-v0', output_dir='output')
trainer.train(total_timesteps=500_000)
```
3. **Export Script** (`export_weights_json.py`):
4. **Requirements** (`requirements.txt`):
```
mini-racer>=0.12.0
gymnasium>=0.29.0
stable-baselines3>=2.2.0
torch>=2.0.0
```
**Step 3: Integration**
Add to game page (`src/pages/game/mygame.astro`):
```astro
<script is:inline src="https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tf.min.js"></script>
<button id="rlAiStartBtn">🧠 RL AI</button>
<script>
import { MyGameWeightsAgent } from '@/lib/ai/agents/MyGameWeightsAgent';
const agent = new MyGameWeightsAgent({
weightsPath: '/models/mygame/model_weights.json'
});
await agent.load();
// Use agent.predict(state) in game loop
</script>
```
**Step 4: Training Workflow**
```bash
npm run build:mygame-core
cd ml-training/mygame-rl
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
python train.py --timesteps 500000
python export_weights_json.py
npm run dev
```
All pages must wrap content with:
```astro
<BaseLayout title="Page Title" description="SEO description">
<!-- content -->
</BaseLayout>
```
For blog posts, add: `articleDate`, `articleAuthor`, `articleTags`
Use `@/*` to reference `src/*` (configured in tsconfig.json)
All RL trainers extend `BaseRLTrainer` and implement:
1. **Single Source of Truth**: Game logic lives ONLY in TypeScript (`{Game}Core.ts`)
2. **100% Consistency**: Python uses PyMiniRacer (V8) to run identical JS code
3. **Gymnasium Standard**: All environments follow OpenAI Gym/Gymnasium interface
4. **JSON Weights**: Simple export format, manual model construction in browser
5. **No Hardcoded Navigation**: Always update Navbar.astro manually when adding pages
Pushes to `main` branch auto-deploy to GitHub Pages via `.github/workflows/deploy.yml`. The workflow runs `npm ci && npm run build` and deploys `dist/`.
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/astro-static-site-developer/raw