phaser-wind 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +170 -413
- package/dist/components/column.d.ts +2 -0
- package/dist/components/column.d.ts.map +1 -0
- package/dist/components/column.js +2 -0
- package/dist/components/column.js.map +1 -0
- package/dist/core/color.d.ts +149 -282
- package/dist/core/color.d.ts.map +1 -1
- package/dist/core/color.js +117 -298
- package/dist/core/color.js.map +1 -1
- package/dist/core/color.spec.js +46 -55
- package/dist/core/color.spec.js.map +1 -1
- package/dist/core/font-size.d.ts +36 -15
- package/dist/core/font-size.d.ts.map +1 -1
- package/dist/core/font-size.js +42 -47
- package/dist/core/font-size.js.map +1 -1
- package/dist/core/font-size.spec.js +55 -43
- package/dist/core/font-size.spec.js.map +1 -1
- package/dist/core/font.d.ts +18 -91
- package/dist/core/font.d.ts.map +1 -1
- package/dist/core/font.js +33 -174
- package/dist/core/font.js.map +1 -1
- package/dist/core/font.spec.js +45 -49
- package/dist/core/font.spec.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/{pallete.d.ts → palette.d.ts} +2 -2
- package/dist/core/{pallete.d.ts.map → palette.d.ts.map} +1 -1
- package/dist/core/{pallete.js → palette.js} +2 -2
- package/dist/core/{pallete.js.map → palette.js.map} +1 -1
- package/dist/core/radius.d.ts +19 -24
- package/dist/core/radius.d.ts.map +1 -1
- package/dist/core/radius.js +20 -28
- package/dist/core/radius.js.map +1 -1
- package/dist/core/radius.spec.js +28 -33
- package/dist/core/radius.spec.js.map +1 -1
- package/dist/core/shadow.d.ts +18 -10
- package/dist/core/shadow.d.ts.map +1 -1
- package/dist/core/shadow.js +29 -19
- package/dist/core/shadow.js.map +1 -1
- package/dist/core/shadow.spec.d.ts +2 -0
- package/dist/core/shadow.spec.d.ts.map +1 -0
- package/dist/core/shadow.spec.js +21 -0
- package/dist/core/shadow.spec.js.map +1 -0
- package/dist/core/spacing.d.ts +22 -29
- package/dist/core/spacing.d.ts.map +1 -1
- package/dist/core/spacing.js +27 -39
- package/dist/core/spacing.js.map +1 -1
- package/dist/core/spacing.spec.js +18 -29
- package/dist/core/spacing.spec.js.map +1 -1
- package/dist/exceptions.d.ts +1 -0
- package/dist/exceptions.d.ts.map +1 -0
- package/dist/exceptions.js +2 -0
- package/dist/exceptions.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/plugin/index.d.ts +2 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/index.js +2 -0
- package/dist/plugin/index.js.map +1 -0
- package/dist/plugin/plugin.d.ts +71 -0
- package/dist/plugin/plugin.d.ts.map +1 -0
- package/dist/plugin/plugin.js +91 -0
- package/dist/plugin/plugin.js.map +1 -0
- package/dist/scene/index.d.ts +2 -0
- package/dist/scene/index.d.ts.map +1 -0
- package/dist/scene/index.js +2 -0
- package/dist/scene/index.js.map +1 -0
- package/dist/scene/scene-with-phaser-wind.d.ts +11 -0
- package/dist/scene/scene-with-phaser-wind.d.ts.map +1 -0
- package/dist/scene/scene-with-phaser-wind.js +11 -0
- package/dist/scene/scene-with-phaser-wind.js.map +1 -0
- package/dist/theme/theme-config.d.ts +24 -48
- package/dist/theme/theme-config.d.ts.map +1 -1
- package/dist/theme/theme-config.js +4 -1
- package/dist/theme/theme-config.js.map +1 -1
- package/dist/theme/theme-manager.d.ts +1 -106
- package/dist/theme/theme-manager.d.ts.map +1 -1
- package/dist/theme/theme-manager.js +1 -187
- package/dist/theme/theme-manager.js.map +1 -1
- package/dist/theme/type.d.ts +48 -0
- package/dist/theme/type.d.ts.map +1 -1
- package/dist/theme/type.js +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
>
|
|
9
9
|
> **Love Tailwind CSS but stuck with Phaser?**
|
|
10
10
|
>
|
|
11
|
-
> **Welcome to Phaser Wind** -
|
|
11
|
+
> **Welcome to Phaser Wind** - bring the joy and simplicity of Tailwind-like design tokens to Phaser games! 🎮✨
|
|
12
12
|
|
|
13
13
|
[](https://www.npmjs.com/package/phaser-wind)
|
|
14
14
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -37,6 +37,7 @@ const title = this.add.text(200, 100, 'Game Title', {
|
|
|
37
37
|
### The Solution 🌟
|
|
38
38
|
|
|
39
39
|
```typescript
|
|
40
|
+
// No theme needed. Just import and go!
|
|
40
41
|
import { Color, FontSize } from 'phaser-wind';
|
|
41
42
|
|
|
42
43
|
// Clean, semantic, consistent!
|
|
@@ -56,15 +57,14 @@ const title = this.add.text(200, 100, 'Game Title', {
|
|
|
56
57
|
|
|
57
58
|
## 🚀 Features
|
|
58
59
|
|
|
59
|
-
- 🎨 **Complete Tailwind Color Palette** -
|
|
60
|
-
- 📐 **Semantic Font Sizes** - From `xs` to `6xl
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
- 🎯 **Smart Token Resolution** - Themes can reference other theme tokens automatically
|
|
60
|
+
- 🎨 **Complete Tailwind-like Color Palette** - 22 families × 11 shades
|
|
61
|
+
- 📐 **Semantic Font Sizes** - From `xs` to `6xl`
|
|
62
|
+
- 🧩 **Default constants ready-to-use** - `Color`, `FontSize`, `Spacing`, `Radius`, `Shadow`
|
|
63
|
+
- 🧭 **Optional theme system (typed)** - Add your own tokens with strong typing
|
|
64
64
|
- 🔧 **TypeScript First** - Full type safety and IntelliSense
|
|
65
|
-
- 🎮 **Phaser Ready** -
|
|
65
|
+
- 🎮 **Phaser Ready** - Global plugin for easy access in scenes
|
|
66
66
|
- 🌈 **Consistent Design** - No more guessing colors and sizes
|
|
67
|
-
- 📦 **Tiny Bundle** -
|
|
67
|
+
- 📦 **Tiny Bundle** - Great DX, minimal overhead
|
|
68
68
|
|
|
69
69
|
---
|
|
70
70
|
|
|
@@ -80,9 +80,9 @@ pnpm add phaser-wind
|
|
|
80
80
|
|
|
81
81
|
---
|
|
82
82
|
|
|
83
|
-
## 🎨 Color System
|
|
83
|
+
## 🎨 Color System (no theme)
|
|
84
84
|
|
|
85
|
-
### Complete
|
|
85
|
+
### Complete Palette
|
|
86
86
|
|
|
87
87
|
Access all Tailwind colors with semantic naming:
|
|
88
88
|
|
|
@@ -110,7 +110,7 @@ const whiteBackground = Color.hex('white'); // 0xFFFFFF
|
|
|
110
110
|
|
|
111
111
|
---
|
|
112
112
|
|
|
113
|
-
## 📏 Font Size System
|
|
113
|
+
## 📏 Font Size System (no theme)
|
|
114
114
|
|
|
115
115
|
### Semantic Sizing
|
|
116
116
|
|
|
@@ -149,457 +149,222 @@ const responsiveText = FontSize.rem('xl'); // 1.25
|
|
|
149
149
|
|
|
150
150
|
---
|
|
151
151
|
|
|
152
|
-
##
|
|
152
|
+
## 🧪 Strong typing (no theme)
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
All APIs are strongly typed. Invalid tokens break at compile time:
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
```ts
|
|
157
|
+
import { Color, FontSize, Spacing, Radius, Shadow } from 'phaser-wind';
|
|
157
158
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
display: 'Orbitron, monospace', // Sci-fi font for headers
|
|
165
|
-
ui: 'Roboto, Arial, sans-serif',
|
|
166
|
-
},
|
|
167
|
-
colors: {
|
|
168
|
-
primary: 'purple-600',
|
|
169
|
-
secondary: 'cyan-500',
|
|
170
|
-
'ui-background': 'slate-900',
|
|
171
|
-
'player-health': 'green-500',
|
|
172
|
-
'enemy-health': 'red-600',
|
|
173
|
-
},
|
|
174
|
-
spacing: {
|
|
175
|
-
xs: 4,
|
|
176
|
-
sm: 8,
|
|
177
|
-
md: 16,
|
|
178
|
-
lg: 24,
|
|
179
|
-
xl: 32,
|
|
180
|
-
},
|
|
181
|
-
typography: {
|
|
182
|
-
heading: {
|
|
183
|
-
fontSize: '2xl',
|
|
184
|
-
fontFamily: 'fonts.display', // 🔗 References fonts.display!
|
|
185
|
-
fontWeight: 600,
|
|
186
|
-
lineHeight: 1.2,
|
|
187
|
-
},
|
|
188
|
-
body: {
|
|
189
|
-
fontSize: 'md',
|
|
190
|
-
fontFamily: 'fonts.primary',
|
|
191
|
-
fontWeight: 400,
|
|
192
|
-
lineHeight: 1.5,
|
|
193
|
-
},
|
|
194
|
-
},
|
|
195
|
-
effects: {
|
|
196
|
-
'glow-primary': {
|
|
197
|
-
blur: 8,
|
|
198
|
-
color: 'colors.primary', // 🔗 References colors.primary!
|
|
199
|
-
alpha: 0.6,
|
|
200
|
-
},
|
|
201
|
-
},
|
|
202
|
-
// Custom categories work too!
|
|
203
|
-
animations: {
|
|
204
|
-
duration: 300,
|
|
205
|
-
easing: 'ease-out',
|
|
206
|
-
},
|
|
207
|
-
});
|
|
159
|
+
// ✅ OK
|
|
160
|
+
Color.rgb('blue-500');
|
|
161
|
+
FontSize.css('lg');
|
|
162
|
+
Spacing.px('16');
|
|
163
|
+
Radius.css('sm');
|
|
164
|
+
Shadow.get('md');
|
|
208
165
|
|
|
209
|
-
//
|
|
210
|
-
|
|
166
|
+
// ❌ Compile-time errors
|
|
167
|
+
// Color.rgb('blue-501');
|
|
168
|
+
// FontSize.css('huge');
|
|
169
|
+
// Spacing.px('97');
|
|
170
|
+
// Radius.css('xxl');
|
|
171
|
+
// Shadow.get('mega');
|
|
211
172
|
```
|
|
212
173
|
|
|
213
|
-
|
|
174
|
+
---
|
|
214
175
|
|
|
215
|
-
|
|
216
|
-
import { Color, Font, FontSize, Spacing, ThemeManager } from 'phaser-wind';
|
|
176
|
+
## 🧱 Token Reference
|
|
217
177
|
|
|
218
|
-
|
|
219
|
-
const primaryColor = Color.rgb('primary'); // Gets colors.primary
|
|
220
|
-
const uiBackground = Color.hex('ui-background'); // Gets colors.ui-background
|
|
178
|
+
### Colors
|
|
221
179
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
180
|
+
- Families: `slate`, `gray`, `zinc`, `neutral`, `stone`, `red`, `orange`, `amber`, `yellow`, `lime`, `green`, `emerald`, `teal`, `cyan`, `sky`, `blue`, `indigo`, `violet`, `purple`, `fuchsia`, `pink`, `rose`
|
|
181
|
+
- Shades: `50`, `100`, `200`, `300`, `400`, `500`, `600`, `700`, `800`, `900`, `950`
|
|
182
|
+
- Special: `black`, `white`
|
|
225
183
|
|
|
226
|
-
|
|
227
|
-
const mediumSpace = Spacing.px('md'); // Gets spacing.md (16px)
|
|
228
|
-
const largeSpace = Spacing.px('lg'); // Gets spacing.lg (24px)
|
|
184
|
+
### Font Size
|
|
229
185
|
|
|
230
|
-
|
|
231
|
-
const headingStyle = {
|
|
232
|
-
fontSize: FontSize.css('2xl'),
|
|
233
|
-
fontFamily: Font.family('display'),
|
|
234
|
-
fontWeight: 'bold',
|
|
235
|
-
};
|
|
186
|
+
- Keys: `xs`, `sm`, `base`, `lg`, `xl`, `2xl`, `3xl`, `4xl`, `5xl`, `6xl`
|
|
236
187
|
|
|
237
|
-
|
|
238
|
-
const animDuration = ThemeManager.getToken('animations.duration'); // 300
|
|
239
|
-
```
|
|
188
|
+
### Spacing
|
|
240
189
|
|
|
241
|
-
|
|
190
|
+
- Keys (px scale ×4): `0`, `px(=1)`, `0.5`, `1`, `1.5`, `2`, `2.5`, `3`, `3.5`, `4`, `5`, `6`, `7`, `8`, `9`, `10`, `11`, `12`, `14`, `16`, `20`, `24`, `28`, `32`, `36`, `40`, `44`, `48`, `52`, `56`, `60`, `64`, `72`, `80`, `96`
|
|
242
191
|
|
|
243
|
-
|
|
244
|
-
// Register multiple themes
|
|
245
|
-
ThemeManager.registerTheme('light', lightTheme);
|
|
246
|
-
ThemeManager.registerTheme('dark', darkTheme);
|
|
247
|
-
ThemeManager.registerTheme('cyberpunk', cyberpunkTheme);
|
|
248
|
-
|
|
249
|
-
// Switch themes instantly
|
|
250
|
-
ThemeManager.setTheme('dark');
|
|
251
|
-
|
|
252
|
-
// Listen for theme changes
|
|
253
|
-
ThemeManager.onThemeChange(newTheme => {
|
|
254
|
-
console.log('Theme changed!', newTheme);
|
|
255
|
-
// Update your game UI here
|
|
256
|
-
});
|
|
192
|
+
### Radius
|
|
257
193
|
|
|
258
|
-
|
|
259
|
-
const themes = ThemeManager.getRegisteredThemes(); // ['light', 'dark', 'cyberpunk']
|
|
260
|
-
```
|
|
194
|
+
- Keys: `none`, `sm`, `default`, `md`, `lg`, `xl`, `2xl`, `3xl`, `full`
|
|
261
195
|
|
|
262
|
-
###
|
|
196
|
+
### Shadow
|
|
263
197
|
|
|
264
|
-
|
|
265
|
-
export class GameScene extends Phaser.Scene {
|
|
266
|
-
create() {
|
|
267
|
-
// Player health bar with theme colors
|
|
268
|
-
const healthWidth = Spacing.px('24'); // 96px
|
|
269
|
-
const healthHeight = Spacing.px('4'); // 16px
|
|
270
|
-
|
|
271
|
-
this.add.rectangle(
|
|
272
|
-
50,
|
|
273
|
-
50,
|
|
274
|
-
healthWidth,
|
|
275
|
-
healthHeight,
|
|
276
|
-
Color.hex('player-health')
|
|
277
|
-
); // Green from theme
|
|
278
|
-
|
|
279
|
-
// Game title with theme typography
|
|
280
|
-
this.add
|
|
281
|
-
.text(400, 50, 'CYBER QUEST', {
|
|
282
|
-
fontSize: FontSize.css('4xl'),
|
|
283
|
-
fontFamily: Font.family('display'),
|
|
284
|
-
color: Color.rgb('primary'), // Purple from theme
|
|
285
|
-
})
|
|
286
|
-
.setOrigin(0.5);
|
|
287
|
-
|
|
288
|
-
// UI button with consistent spacing and colors
|
|
289
|
-
this.createButton(
|
|
290
|
-
400,
|
|
291
|
-
400,
|
|
292
|
-
'START GAME',
|
|
293
|
-
Spacing.px('16'), // 64px width
|
|
294
|
-
Spacing.px('6') // 24px height
|
|
295
|
-
);
|
|
296
|
-
}
|
|
198
|
+
- Default keys: `sm`, `md`, `lg`, `xl`, `2xl`, `inner`
|
|
297
199
|
|
|
298
|
-
|
|
299
|
-
x: number,
|
|
300
|
-
y: number,
|
|
301
|
-
text: string,
|
|
302
|
-
width: number,
|
|
303
|
-
height: number
|
|
304
|
-
) {
|
|
305
|
-
const button = this.add
|
|
306
|
-
.rectangle(x, y, width, height, Color.hex('ui-background'))
|
|
307
|
-
.setInteractive()
|
|
308
|
-
.on('pointerover', () => button.setFillStyle(Color.hex('secondary')))
|
|
309
|
-
.on('pointerout', () => button.setFillStyle(Color.hex('ui-background')));
|
|
310
|
-
|
|
311
|
-
this.add
|
|
312
|
-
.text(x, y, text, {
|
|
313
|
-
fontSize: FontSize.css('base'),
|
|
314
|
-
fontFamily: Font.family('primary'),
|
|
315
|
-
color: Color.rgb('primary'),
|
|
316
|
-
})
|
|
317
|
-
.setOrigin(0.5);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
### 🎨 **Pre-built Themes**
|
|
323
|
-
|
|
324
|
-
```typescript
|
|
325
|
-
import { defaultLightTheme, defaultDarkTheme } from 'phaser-wind';
|
|
326
|
-
|
|
327
|
-
// Light theme with professional colors
|
|
328
|
-
ThemeManager.init(defaultLightTheme);
|
|
200
|
+
---
|
|
329
201
|
|
|
330
|
-
|
|
331
|
-
ThemeManager.init(defaultDarkTheme);
|
|
202
|
+
## 🎨 Theming
|
|
332
203
|
|
|
333
|
-
|
|
334
|
-
const winterTheme = ThemeManager.extendCurrentTheme({
|
|
335
|
-
'colors.primary': 'blue-400',
|
|
336
|
-
'colors.secondary': 'cyan-300',
|
|
337
|
-
'colors.accent': 'white',
|
|
338
|
-
});
|
|
339
|
-
```
|
|
204
|
+
Phaser Wind also provides a typed theme system via a Phaser plugin. You get the same API surface (`color`, `fontSize`, `spacing`, `radius`, `font`, `shadow`) but narrowed to your custom tokens.
|
|
340
205
|
|
|
341
|
-
###
|
|
206
|
+
### 1) Create a theme
|
|
342
207
|
|
|
343
|
-
|
|
208
|
+
```ts
|
|
209
|
+
import { createTheme, type CreateTheme } from 'phaser-wind';
|
|
344
210
|
|
|
345
|
-
|
|
346
|
-
|
|
211
|
+
export const theme = createTheme({
|
|
212
|
+
fonts: {
|
|
213
|
+
primary: 'Inter, system-ui, sans-serif',
|
|
214
|
+
display: 'Orbitron, monospace',
|
|
215
|
+
},
|
|
216
|
+
fontSizes: {
|
|
217
|
+
// optional overrides
|
|
218
|
+
},
|
|
347
219
|
colors: {
|
|
348
|
-
|
|
220
|
+
primary: 'blue-600',
|
|
221
|
+
background: 'slate-900',
|
|
349
222
|
danger: 'red-500',
|
|
350
223
|
},
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
},
|
|
224
|
+
spacing: {
|
|
225
|
+
gutter: 24,
|
|
226
|
+
},
|
|
227
|
+
radius: {
|
|
228
|
+
card: 12,
|
|
357
229
|
},
|
|
358
230
|
effects: {
|
|
359
|
-
|
|
360
|
-
color: 'colors.brand', // 🔗 Auto-resolves to purple-600
|
|
361
|
-
blur: 8,
|
|
362
|
-
},
|
|
231
|
+
glow: { blur: 8, offsetX: 0, offsetY: 0, alpha: 0.6 },
|
|
363
232
|
},
|
|
364
|
-
});
|
|
233
|
+
} satisfies CreateTheme<any>);
|
|
234
|
+
|
|
235
|
+
export type ThemeType = typeof theme;
|
|
365
236
|
```
|
|
366
237
|
|
|
367
|
-
|
|
238
|
+
### 2) Install the plugin in Phaser
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
import {
|
|
242
|
+
PhaserWindPlugin,
|
|
243
|
+
PHASER_WIND_KEY,
|
|
244
|
+
defaultLightTheme,
|
|
245
|
+
} from 'phaser-wind';
|
|
246
|
+
import { theme } from './theme';
|
|
247
|
+
|
|
248
|
+
new Phaser.Game({
|
|
249
|
+
plugins: {
|
|
250
|
+
global: [
|
|
251
|
+
{
|
|
252
|
+
key: PHASER_WIND_KEY,
|
|
253
|
+
plugin: PhaserWindPlugin,
|
|
254
|
+
mapping: PHASER_WIND_KEY, // scene.pw
|
|
255
|
+
data: { theme }, // or { theme: defaultLightTheme }
|
|
256
|
+
},
|
|
257
|
+
],
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
```
|
|
368
261
|
|
|
369
|
-
|
|
262
|
+
### 3) How to get strong types in your scene
|
|
370
263
|
|
|
371
|
-
|
|
264
|
+
#### 3.1 Lazy way. Define a module and all scenes should be have the "pw" instance
|
|
372
265
|
|
|
373
|
-
```
|
|
374
|
-
|
|
266
|
+
```ts
|
|
267
|
+
// src/my-theme.ts
|
|
268
|
+
import 'phaser';
|
|
269
|
+
import type { PhaserWindPlugin } from 'phaser-wind';
|
|
270
|
+
import type { ThemeType } from './theme';
|
|
375
271
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
.text(400, 100, 'SPACE RAIDERS', {
|
|
381
|
-
fontSize: FontSize.css('5xl'),
|
|
382
|
-
fill: Color.rgb('yellow-400'),
|
|
383
|
-
stroke: Color.rgb('yellow-800'),
|
|
384
|
-
strokeThickness: 2,
|
|
385
|
-
})
|
|
386
|
-
.setOrigin(0.5);
|
|
387
|
-
|
|
388
|
-
// Score display
|
|
389
|
-
this.add.text(50, 50, 'Score: 12,500', {
|
|
390
|
-
fontSize: FontSize.css('xl'),
|
|
391
|
-
fill: Color.rgb('green-400'),
|
|
392
|
-
});
|
|
393
|
-
|
|
394
|
-
// Health bar background
|
|
395
|
-
const healthBg = this.add.graphics();
|
|
396
|
-
healthBg.fillStyle(Color.hex('red-900'));
|
|
397
|
-
healthBg.fillRect(50, 100, 200, 20);
|
|
398
|
-
|
|
399
|
-
// Health bar fill
|
|
400
|
-
const healthFill = this.add.graphics();
|
|
401
|
-
healthFill.fillStyle(Color.hex('red-500'));
|
|
402
|
-
healthFill.fillRect(52, 102, 156, 16); // 80% health
|
|
403
|
-
|
|
404
|
-
// Game over screen
|
|
405
|
-
this.add.rectangle(400, 300, 600, 400, Color.hex('slate-900'), 0.9);
|
|
406
|
-
|
|
407
|
-
this.add
|
|
408
|
-
.text(400, 250, 'GAME OVER', {
|
|
409
|
-
fontSize: FontSize.css('4xl'),
|
|
410
|
-
fill: Color.rgb('red-500'),
|
|
411
|
-
})
|
|
412
|
-
.setOrigin(0.5);
|
|
413
|
-
|
|
414
|
-
this.add
|
|
415
|
-
.text(400, 320, 'Final Score: 12,500', {
|
|
416
|
-
fontSize: FontSize.css('2xl'),
|
|
417
|
-
fill: Color.rgb('slate-300'),
|
|
418
|
-
})
|
|
419
|
-
.setOrigin(0.5);
|
|
272
|
+
const theme = const theme = createTheme({
|
|
273
|
+
colors: {
|
|
274
|
+
brand: 'purple-600',
|
|
275
|
+
danger: 'red-500',
|
|
420
276
|
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
### Button System
|
|
277
|
+
});
|
|
278
|
+
export type ThemeType = typeof theme;
|
|
425
279
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
scene: Phaser.Scene,
|
|
430
|
-
x: number,
|
|
431
|
-
y: number,
|
|
432
|
-
text: string,
|
|
433
|
-
variant: 'primary' | 'secondary' | 'danger' = 'primary'
|
|
434
|
-
) {
|
|
435
|
-
const colors = {
|
|
436
|
-
primary: {
|
|
437
|
-
bg: Color.hex('blue-600'),
|
|
438
|
-
bgHover: Color.hex('blue-700'),
|
|
439
|
-
text: Color.rgb('white'),
|
|
440
|
-
},
|
|
441
|
-
secondary: {
|
|
442
|
-
bg: Color.hex('slate-600'),
|
|
443
|
-
bgHover: Color.hex('slate-700'),
|
|
444
|
-
text: Color.rgb('slate-100'),
|
|
445
|
-
},
|
|
446
|
-
danger: {
|
|
447
|
-
bg: Color.hex('red-600'),
|
|
448
|
-
bgHover: Color.hex('red-700'),
|
|
449
|
-
text: Color.rgb('white'),
|
|
450
|
-
},
|
|
451
|
-
};
|
|
452
|
-
|
|
453
|
-
const style = colors[variant];
|
|
454
|
-
|
|
455
|
-
// Background
|
|
456
|
-
this.background = scene.add
|
|
457
|
-
.rectangle(x, y, 200, 50, style.bg)
|
|
458
|
-
.setInteractive()
|
|
459
|
-
.on('pointerover', () => this.background.setFillStyle(style.bgHover))
|
|
460
|
-
.on('pointerout', () => this.background.setFillStyle(style.bg));
|
|
461
|
-
|
|
462
|
-
// Text
|
|
463
|
-
this.text = scene.add
|
|
464
|
-
.text(x, y, text, {
|
|
465
|
-
fontSize: FontSize.css('lg'),
|
|
466
|
-
fill: style.text,
|
|
467
|
-
})
|
|
468
|
-
.setOrigin(0.5);
|
|
280
|
+
declare module 'phaser' {
|
|
281
|
+
interface Scene {
|
|
282
|
+
pw: PhaserWindPlugin<ThemeType>;
|
|
469
283
|
}
|
|
470
284
|
}
|
|
471
285
|
|
|
472
|
-
//
|
|
473
|
-
const playButton = new GameButton(this, 400, 200, 'PLAY', 'primary');
|
|
474
|
-
const settingsButton = new GameButton(this, 400, 280, 'SETTINGS', 'secondary');
|
|
475
|
-
const quitButton = new GameButton(this, 400, 360, 'QUIT', 'danger');
|
|
476
|
-
```
|
|
477
|
-
|
|
478
|
-
### Particle Effects with Color Harmony
|
|
286
|
+
// In your scene
|
|
479
287
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
this.
|
|
483
|
-
speed: { min: 50, max: 100 },
|
|
484
|
-
tint: [
|
|
485
|
-
Color.hex('blue-400'),
|
|
486
|
-
Color.hex('blue-500'),
|
|
487
|
-
Color.hex('blue-600'),
|
|
488
|
-
Color.hex('cyan-400'),
|
|
489
|
-
Color.hex('cyan-500'),
|
|
490
|
-
],
|
|
491
|
-
lifespan: 1000,
|
|
492
|
-
});
|
|
288
|
+
class MyCustomScene extends Phaser.Scene {
|
|
289
|
+
create(): void {
|
|
290
|
+
this.pw // <-- Valid instance in your ts file
|
|
493
291
|
```
|
|
494
292
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
## 🎮 Integration with Phaser
|
|
293
|
+
#### 3.1 - Cast way
|
|
498
294
|
|
|
499
|
-
|
|
295
|
+
The original `Phaser.Scene` does not know the `pw` from Phaser-wind. You can make a simple cast to solve this problem
|
|
500
296
|
|
|
501
|
-
```
|
|
502
|
-
import
|
|
297
|
+
```ts
|
|
298
|
+
import Phaser from 'phaser';
|
|
299
|
+
import { type ThemeType } from 'src/theme.ts' // In your project
|
|
503
300
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
301
|
+
class MyCustomScene extends Phaser.Scene {
|
|
302
|
+
create(): void {
|
|
303
|
+
const { pw } = (this as unknown as SceneWithPhaserWind<Theme>); // cast to get the pw property
|
|
304
|
+
this.cameras.main.setBackgroundColor(pw.color.slate(900));
|
|
508
305
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
Color.hex('slate-700') // bottom-right
|
|
517
|
-
);
|
|
518
|
-
bg.fillRect(0, 0, this.cameras.main.width, this.cameras.main.height);
|
|
519
|
-
|
|
520
|
-
// Consistent UI elements
|
|
521
|
-
this.createTitle();
|
|
522
|
-
this.createMenu();
|
|
523
|
-
}
|
|
306
|
+
this.add
|
|
307
|
+
.text(300, 100, 'Primary color', {
|
|
308
|
+
fontSize: pw.fontSize.css('2xl'), // use the pw property to get the font size
|
|
309
|
+
color: pw.color.rgb('primary'), // use the pw property to get the color with type safety
|
|
310
|
+
})
|
|
311
|
+
.setOrigin(0.5);
|
|
312
|
+
```
|
|
524
313
|
|
|
525
|
-
|
|
526
|
-
this.add
|
|
527
|
-
.text(this.cameras.main.centerX, 150, 'MY AWESOME GAME', {
|
|
528
|
-
fontSize: FontSize.css('4xl'),
|
|
529
|
-
fill: Color.rgb('yellow-400'),
|
|
530
|
-
stroke: Color.rgb('yellow-700'),
|
|
531
|
-
strokeThickness: 3,
|
|
532
|
-
})
|
|
533
|
-
.setOrigin(0.5);
|
|
534
|
-
}
|
|
314
|
+
#### 3.2 - Inheritance way
|
|
535
315
|
|
|
536
|
-
|
|
537
|
-
const menuItems = ['Play', 'Options', 'Credits', 'Quit'];
|
|
538
|
-
|
|
539
|
-
menuItems.forEach((item, index) => {
|
|
540
|
-
this.add
|
|
541
|
-
.text(this.cameras.main.centerX, 250 + index * 60, item, {
|
|
542
|
-
fontSize: FontSize.css('xl'),
|
|
543
|
-
fill: Color.rgb('slate-300'),
|
|
544
|
-
})
|
|
545
|
-
.setOrigin(0.5)
|
|
546
|
-
.setInteractive()
|
|
547
|
-
.on('pointerover', function () {
|
|
548
|
-
this.setTint(Color.hex('yellow-400'));
|
|
549
|
-
})
|
|
550
|
-
.on('pointerout', function () {
|
|
551
|
-
this.clearTint();
|
|
552
|
-
});
|
|
553
|
-
});
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
```
|
|
316
|
+
Phaser-wind export an abstract class to type the `Phaser.Scene` and add the attribute `pw`.
|
|
557
317
|
|
|
558
|
-
|
|
318
|
+
```ts
|
|
319
|
+
import Phaser from 'phaser';
|
|
320
|
+
import { type ThemeType } from 'src/theme.ts' // In your project
|
|
559
321
|
|
|
560
|
-
|
|
322
|
+
class PreviewScene extends SceneWithPhaserWind<ThemeType> { // Inherit from SceneWithPhaserWind to get the pw property
|
|
323
|
+
create(): void {
|
|
324
|
+
const { color, fontSize, spacing, radius, font, shadow } = this.pw; // Don't need to cast because we're using the generic type
|
|
561
325
|
|
|
562
|
-
|
|
326
|
+
// ✅ Type-narrowed to your theme
|
|
327
|
+
color.rgb('primary');
|
|
328
|
+
fontSize.css('lg');
|
|
329
|
+
spacing.px('gutter');
|
|
330
|
+
radius.css('card');
|
|
331
|
+
font.family('display');
|
|
332
|
+
shadow.get('glow');
|
|
563
333
|
|
|
564
|
-
|
|
565
|
-
//
|
|
566
|
-
|
|
567
|
-
background: Color.hex('slate-900'),
|
|
568
|
-
surface: Color.hex('slate-800'),
|
|
569
|
-
primary: Color.hex('blue-500'),
|
|
570
|
-
secondary: Color.hex('slate-600'),
|
|
571
|
-
text: Color.rgb('slate-100'),
|
|
572
|
-
textMuted: Color.rgb('slate-400'),
|
|
573
|
-
};
|
|
574
|
-
|
|
575
|
-
const lightTheme = {
|
|
576
|
-
background: Color.hex('slate-50'),
|
|
577
|
-
surface: Color.hex('white'),
|
|
578
|
-
primary: Color.hex('blue-600'),
|
|
579
|
-
secondary: Color.hex('slate-200'),
|
|
580
|
-
text: Color.rgb('slate-900'),
|
|
581
|
-
textMuted: Color.rgb('slate-600'),
|
|
582
|
-
};
|
|
334
|
+
// ❌ Compile-time errors
|
|
335
|
+
// color.rgb('blue-501');
|
|
336
|
+
// spacing.px('unknown');
|
|
583
337
|
```
|
|
584
338
|
|
|
585
|
-
###
|
|
339
|
+
### 🎮 **Real Game Example**
|
|
586
340
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
341
|
+
You can check some examples in our [Storybook in this clicking here](https://renatocassino.github.io/phaser-toolkit).
|
|
342
|
+
|
|
343
|
+
### 🎨 **Pre-built Themes**
|
|
344
|
+
|
|
345
|
+
```ts
|
|
346
|
+
import {
|
|
347
|
+
PhaserWindPlugin,
|
|
348
|
+
PHASER_WIND_KEY,
|
|
349
|
+
defaultLightTheme,
|
|
350
|
+
// or defaultDarkTheme
|
|
351
|
+
} from 'phaser-wind';
|
|
352
|
+
import { theme } from './theme';
|
|
353
|
+
|
|
354
|
+
new Phaser.Game({
|
|
355
|
+
plugins: {
|
|
356
|
+
global: [
|
|
357
|
+
{
|
|
358
|
+
key: PHASER_WIND_KEY,
|
|
359
|
+
plugin: PhaserWindPlugin,
|
|
360
|
+
mapping: PHASER_WIND_KEY, // scene.pw
|
|
361
|
+
data: { theme: defaultLighTheme }, // or { theme: defaultDarkTheme }
|
|
362
|
+
},
|
|
363
|
+
],
|
|
364
|
+
},
|
|
598
365
|
});
|
|
599
366
|
```
|
|
600
367
|
|
|
601
|
-
---
|
|
602
|
-
|
|
603
368
|
## 🤝 Why "Wind" instead of "Tailwind"?
|
|
604
369
|
|
|
605
370
|
We love Tailwind CSS, but we're not affiliated with them. "Phaser Wind" captures the essence:
|
|
@@ -627,16 +392,6 @@ Plus, `phaser-wind` is way easier to type than `phaser-tailwind-css-design-token
|
|
|
627
392
|
|
|
628
393
|
---
|
|
629
394
|
|
|
630
|
-
## 🔮 Coming Soon
|
|
631
|
-
|
|
632
|
-
- 📐 **Layout Utilities** - Flexbox-inspired alignment helpers
|
|
633
|
-
- 📱 **Responsive Utilities** - Breakpoint-based design tokens
|
|
634
|
-
- ⚡ **Animation Presets** - Smooth, consistent transitions
|
|
635
|
-
- 🎮 **Component Library** - Pre-built Phaser components with theme support
|
|
636
|
-
- 🔧 **CLI Tool** - Generate themes and components from the command line
|
|
637
|
-
|
|
638
|
-
---
|
|
639
|
-
|
|
640
395
|
## 🤝 Contributing
|
|
641
396
|
|
|
642
397
|
We'd love your help making Phaser Wind even better!
|
|
@@ -653,6 +408,8 @@ We'd love your help making Phaser Wind even better!
|
|
|
653
408
|
|
|
654
409
|
MIT © [CassinoDev](https://github.com/cassinodev)
|
|
655
410
|
|
|
411
|
+
Do you want to play? Go to [games.cassino.dev](https://games.cassino.dev).
|
|
412
|
+
|
|
656
413
|
---
|
|
657
414
|
|
|
658
415
|
## 🌟 Show Your Support
|