用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/feliperyba/ralph-orchestra --skill dev-phaser-ui-creation命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Complete Developer workflow orchestration - task research sequence, implementation flow, validation gates, PRD synchronization, exit conditions.
Complete Game Designer workflow - skill invocation protocol, GDD creation, playtest flow with GDD review, design sessions. MUST load before starting assignments.
Complete PM Coordinator workflow - task assignment, project orchestration, PRD management, worker coordination. Use proactively when starting PM agent work.
正在显示 SKILL.md
基于 SOC 职业分类
| name | dev-phaser-ui-creation |
| description | UI containers, text objects, buttons, and DOM element integration |
"Build responsive game UI with Phaser's UI components."
// Pure HTML/CSS UI without Phaser integration
class GameUI {
private container: HTMLElement;
private scoreElement: HTMLElement;
private healthFillElement: HTMLElement;
private buttons: HTMLElement[] = [];
constructor() {
// Create UI container
this.container = document.createElement('div');
this.container.id = 'game-ui';
this.container.style.position = 'absolute';
this.container.style.top = '0';
this.container.style.left = '0';
this.container.style.width = '100%';
this.container.style.pointerEvents = 'none'; // Let clicks pass through
document.body.appendChild(this.container);
// Score display
this.scoreElement = document.createElement('div');
this.scoreElement.className = 'score-display';
this.scoreElement.textContent = 'Score: 0';
this.container.appendChild(this.scoreElement);
// Health bar
const healthBar = document.createElement('div');
healthBar.className = 'health-bar';
healthBar.innerHTML = `
<div class="health-bg">
<div class="health-fill"></div>
</div>
`;
this.container.appendChild(healthBar);
this.healthFillElement = healthBar.querySelector('.health-fill')!;
// Add CSS manually
const style = document.createElement('style');
style.textContent = `
.score-display {
position: absolute;
top: 16px;
left: 16px;
font-size: 32px;
font-family: Arial;
color: white;
text-shadow: 2px 2px 0 black;
}
.health-bar {
position: absolute;
top: 60px;
left: 16px;
width: 200px;
height: 20px;
}
.health-bg {
width: 100%;
height: 100%;
background: #333;
border: 2px solid white;
}
.health-fill {
width: 100%;
height: 100%;
background: #0f0;
transition: width 0.2s;
}
`;
document.head.appendChild(style);
// Buttons need pointer events
const startButton = document.createElement('button');
startButton.textContent = 'Start Game';
startButton.style.pointerEvents = 'auto';
startButton.onclick = () => this.onStartGame();
this.container.appendChild(startButton);
this.buttons.push(startButton);
// Manual sync with game state
// Manual responsive positioning
// No scene lifecycle integration
}
updateScore(score: number) {
this.scoreElement.textContent = `Score: ${score}`;
}
updateHealth(current: number, max: number) {
const percent = (current / max) * 100;
this.healthFillElement.style.width = `${percent}%`;
}
// Manual cleanup required
destroy() {
this.container.remove();
}
// No integration with Phaser scenes
// Manual positioning for camera
// No depth sorting with game objects
}
// Problems:
// - No integration with Phaser scenes
// - Manual DOM manipulation
// - Separate CSS file or inline styles
// - No access to Phaser textures
// - Can't use Phaser tweens on UI
// - Manual sync with game state
// - No depth control vs game objects
// - Performance: separate render layer
// Phaser UI is fully integrated
export class UIScene extends Phaser.Scene {
private scoreText!: Phaser.GameObjects.Text;
private healthBar!: Phaser.GameObjects.Graphics;
create() {
// Score text - ONE line!
this.scoreText = this.add.text(16, 16, 'Score: 0', {
fontSize: '32px',
fontFamily: 'Arial',
color: '#ffffff',
fontStyle: 'bold',
stroke: '#000000',
strokeThickness: 4
});
// Health bar with Phaser graphics
this.healthBar = this.add.graphics();
this.updateHealth(100, 100);
// Button with built-in interaction
const startBtn = this.add.(, , , {
: ,
: ,
: ,
: { : , : }
});
startBtn.();
startBtn.({ : });
startBtn.(, {
..({
: startBtn,
: ,
:
});
startBtn.({ : });
});
startBtn.(, {
..({
: startBtn,
: ,
:
});
startBtn.({ : });
});
startBtn.(, {
..();
});
...([., ., startBtn]);
}
() {
..();
..();
..(, , , );
percent = current / max;
color = percent > ? :
percent > ? : ;
..(color);
..(, , * percent, );
..(, );
..(, , , );
}
() {
..();
..({
: .,
: ,
: ,
:
});
}
}
Use when:
create() {
// Text object
const score = this.add.text(16, 16, 'Score: 0', {
fontSize: '32px',
color: '#fff'
});
// Interactive button
const button = this.add.text(400, 300, 'Start', {
backgroundColor: '#00f',
padding: { x: 10, y: 5 }
});
button.setOrigin(0.5);
button.setInteractive();
button.on('pointerdown', () => this.startGame());
}
| Need | Use |
|---|---|
| Simple text | add.text() |
| Styling text | Text style config |
| Interactive UI | setInteractive() |
| Complex layouts | Container or HTML overlay |
| Responsive UI | Scale manager + resize events |
export class UIScene extends Phaser.Scene {
private scoreText!: Phaser.GameObjects.Text;
private healthBar!: Phaser.GameObjects.Graphics;
private health = 100;
private maxHealth = 100;
create() {
// Score display
this.scoreText = this.add.text(16, 16, "Score: 0", {
fontSize: "32px",
fontFamily: "Arial",
color: "#ffffff",
fontStyle: "bold",
});
// Health bar background
this.healthBar = this.add.graphics();
this.updateHealthBar();
// Timer text
const timerText = this.add.text(this.scale.width - , , , {
: ,
: ,
});
timerText.(, );
}
() {
..();
}
() {
..();
..();
..(, , , );
healthPercent = . / .;
color =
healthPercent >
?
: healthPercent >
?
: ;
..(color);
..(, , * healthPercent, );
..(, );
..(, , , );
}
}
export class MenuScene extends Phaser.Scene {
create() {
// Button background style
const buttonStyle = {
backgroundColor: "#4444ff",
color: "#ffffff",
fontSize: "24px",
padding: { x: 20, y: 10 },
borderRadius: 5,
};
const hoverStyle = {
backgroundColor: "#6666ff",
color: "#ffff00",
};
// Create buttons
const startBtn = this.createButton(400, 200, "Start Game", buttonStyle);
startBtn.on("pointerdown", () => {
this.scene.start("GameScene");
});
const optionsBtn = this.createButton(400, 280, "Options", buttonStyle);
optionsBtn.on("pointerdown", () => {
this..();
});
quitBtn = .(, , , buttonStyle);
quitBtn.(, {
..();
});
}
(
: ,
: ,
: ,
: ,
): .. {
button = ..(x, y, text, style);
button.();
button.({ : });
button.(, {
button.({ : , : });
button.();
});
button.(, {
button.({ : , : });
button.();
});
button.(, {
button.();
});
button.(, {
button.();
});
button;
}
}
export class UIScene extends Phaser.Scene {
create() {
// Container for HUD elements
const hudContainer = this.add.container(0, 0);
// Health display
const healthBg = this.add.rectangle(20, 20, 200, 20, 0x333333);
const healthFill = this.add.rectangle(20, 20, 180, 16, 0x00ff00);
healthFill.setOrigin(0, 0.5);
const healthText = this.add.text(120, 20, "100/100", {
fontSize: "14px",
color: "#fff",
});
healthText.setOrigin(0.5);
// Score display
const scoreLabel = this.add.(, , , {
: ,
: ,
});
scoreValue = ..(, , , {
: ,
: ,
});
hudContainer.([
healthBg,
healthFill,
healthText,
scoreLabel,
scoreValue,
]);
hudContainer.();
}
}
export class DialogScene extends Phaser.Scene {
private dialogBox!: Phaser.GameObjects.Container;
private dialogText!: Phaser.GameObjects.Text;
private continueText!: Phaser.GameObjects.Text;
private isTyping = false;
private typingSpeed = 30;
create() {
// Semi-transparent overlay
const overlay = this.add.rectangle(
this.scale.width / 2,
this.scale.height / 2,
this.scale.width,
this.scale.height,
0x000000,
0.5,
);
// Dialog background
const dialogBg = this.add.rectangle(
this.scale. / ,
.. - ,
.. - ,
,
,
);
dialogBg.(, );
. = ..(
.. / ,
.. - ,
,
{
: ,
: ,
: ,
: { : .. - },
},
);
..(, );
. = ..(
.. / ,
.. - ,
,
{
: ,
: ,
},
);
..();
..();
. = ..(, );
..([dialogBg, ., .]);
..();
spaceKey = ..!.();
spaceKey.(, .());
}
() {
..();
..();
. = ;
index = ;
timer = ..({
: .,
: text. - ,
: {
index++;
..(text.(, index));
(index >= text.) {
. = ;
..();
timer.();
}
},
});
}
() {
(.) {
..();
. = ;
..();
} {
..();
}
}
}
export class GameScene extends Phaser.Scene {
private domElement!: HTMLElement;
create() {
// Create HTML overlay
this.domElement = this.add
.dom(this.scale.width / 2, this.scale.height / 2)
.createElement("div");
this.domElement.setHTML(`
<div class="ui-overlay">
<h1>Game Paused</h1>
<button id="resume-btn">Resume</button>
<button id="quit-btn">Quit</button>
</div>
`);
// Add CSS
this.domElement.setStyle(`
.ui-overlay {
background: rgba(0, 0, 0, 0.8);
padding: 40px;
border-radius: 10px;
text-align: center;
color: white;
font-family: Arial, sans-serif;
}
h1 { margin: 0 0 20px 0; }
button {
padding: 10px 20px;
margin: 5px;
font-size: 16px;
cursor: pointer;
background: #4444ff;
color: white;
border: none;
border-radius: 5px;
}
button:hover {
background: #6666ff;
}
`);
// Hide initially
this.domElement.setVisible(false);
// Button handlers
..().(, {
.();
});
..().(, {
.();
});
}
() {
..();
..();
}
() {
..();
..();
}
() {
..();
}
}
❌ DON'T:
✅ DO:
create() {
// Position relative to screen size
const scoreText = this.add.text(
this.scale.width * 0.02, // 2% from left
this.scale.height * 0.02, // 2% from top
'Score: 0'
);
// Handle resize
this.scale.on('resize', (gameSize: Phaser.Structs.Size) => {
scoreText.setPosition(
gameSize.width * 0.02,
gameSize.height * 0.02
);
});
}
const TEXT_STYLES = {
HEADER: {
fontSize: "48px",
fontFamily: "Arial",
color: "#ffffff",
fontStyle: "bold",
stroke: "#000000",
strokeThickness: 4,
},
BODY: {
fontSize: "18px",
fontFamily: "Arial",
color: "#cccccc",
align: "center",
},
BUTTON: {
fontSize: "24px",
fontFamily: "Arial",
color: "#ffffff",
backgroundColor: "#4444ff",
padding: { x: 20, y: 10 },
},
};
class Button extends Phaser.GameObjects.Container {
private background: Phaser.GameObjects.Rectangle;
private text: Phaser.GameObjects.Text;
constructor(
scene: Phaser.Scene,
x: number,
y: number,
width: number,
height: number,
text: string,
onClick: () => void,
) {
super(scene, x, y);
scene.add.existing(this);
// Background
this.background = scene.add.rectangle(0, 0, width, height, 0x4444ff);
this.background.setStrokeStyle(2, 0x6666ff);
this.background.setInteractive({ useHandCursor: });
. = scene..(, , text, {
: ,
: ,
});
..();
.([., .]);
..(, .());
..(, .());
..(, .());
..(, {
.();
();
});
}
() {
..();
}
() {
..();
}
() {
.();
}
() {
.();
}
}
| Property | Type | Description |
|---|---|---|
fontFamily | string | Font name |
fontSize | string | Size with unit (e.g., '24px') |
color | string | Text color (hex) |
fontStyle | string | 'bold', 'italic', etc. |
align | string | 'left', 'center', 'right' |
backgroundColor | string | Background color |
padding | object | { x, y } padding |
lineSpacing | number | Space between lines |
stroke | string | Outline color |
strokeThickness | number | Outline width |
shadow | object | Shadow config |
wordWrap | object | { width } for wrapping |