@littlepartytime/sdk 2.2.1 → 2.2.3
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/GAME_DEV_GUIDE.md +133 -49
- package/dist/interfaces.d.ts +4 -4
- package/dist/interfaces.d.ts.map +1 -1
- package/package.json +1 -1
package/GAME_DEV_GUIDE.md
CHANGED
|
@@ -23,10 +23,10 @@ my-game/
|
|
|
23
23
|
├── vitest.config.ts # Test configuration
|
|
24
24
|
├── tsconfig.json
|
|
25
25
|
├── assets/ # Game images and custom assets
|
|
26
|
-
│ ├── icon.png # 1:1 (
|
|
27
|
-
│ ├── banner.
|
|
28
|
-
│ ├── cover.
|
|
29
|
-
│ ├── splash.
|
|
26
|
+
│ ├── icon.png # 1:1 (512x512+) - game list icon
|
|
27
|
+
│ ├── banner.webp # 16:9 (1280x720+) - lobby banner
|
|
28
|
+
│ ├── cover.webp # 21:9 (1260x540+) - store/featured cover
|
|
29
|
+
│ ├── splash.webp # 9:21 (1080x2520+) - loading screen
|
|
30
30
|
│ ├── cards/ # Custom game assets (optional)
|
|
31
31
|
│ │ ├── king.png
|
|
32
32
|
│ │ └── queen.png
|
|
@@ -76,10 +76,10 @@ const config: GameConfig = {
|
|
|
76
76
|
name: "My Game", // Display name (Chinese preferred for CN users)
|
|
77
77
|
description: "...", // Brief description
|
|
78
78
|
assets: {
|
|
79
|
-
icon: "assets/icon.png",
|
|
80
|
-
banner: "assets/banner.
|
|
81
|
-
cover: "assets/cover.
|
|
82
|
-
splash: "assets/splash.
|
|
79
|
+
icon: "assets/icon.png", // 1:1 (512x512+), PNG recommended
|
|
80
|
+
banner: "assets/banner.webp", // 16:9 (1280x720+), WebP recommended
|
|
81
|
+
cover: "assets/cover.webp", // 21:9 (1260x540+), WebP recommended
|
|
82
|
+
splash: "assets/splash.webp", // 9:21 (1080x2520+), WebP recommended
|
|
83
83
|
},
|
|
84
84
|
minPlayers: 2,
|
|
85
85
|
maxPlayers: 6,
|
|
@@ -253,12 +253,12 @@ export default function GameRenderer({ platform, state }: GameRendererProps) {
|
|
|
253
253
|
[platform]
|
|
254
254
|
);
|
|
255
255
|
|
|
256
|
-
// Render game UI
|
|
256
|
+
// Render game UI — use inline styles + CSS variables for consistent styling
|
|
257
257
|
return (
|
|
258
|
-
<div>
|
|
258
|
+
<div style={{ color: "var(--text-primary)" }}>
|
|
259
259
|
{/* Your game UI here */}
|
|
260
|
-
{/* Use
|
|
261
|
-
{/*
|
|
260
|
+
{/* Use inline styles with CSS variables from the platform design tokens */}
|
|
261
|
+
{/* See "Renderer Styling Guide" section below for details */}
|
|
262
262
|
</div>
|
|
263
263
|
);
|
|
264
264
|
}
|
|
@@ -594,10 +594,10 @@ The `.zip` upload package contains:
|
|
|
594
594
|
├── rules.md # Game rules
|
|
595
595
|
├── bundle.js # Client-side bundle
|
|
596
596
|
├── engine.cjs # Server-side engine
|
|
597
|
-
├── icon.png
|
|
598
|
-
├── banner.png
|
|
599
|
-
├── cover.png
|
|
600
|
-
├── splash.png
|
|
597
|
+
├── icon.png|.webp # 1:1 game icon
|
|
598
|
+
├── banner.png|.webp # 16:9 banner
|
|
599
|
+
├── cover.png|.webp # 21:9 cover
|
|
600
|
+
├── splash.png|.webp # 9:21 splash screen
|
|
601
601
|
└── assets/ # Custom game assets (if any)
|
|
602
602
|
├── cards/
|
|
603
603
|
│ └── king.png
|
|
@@ -657,21 +657,21 @@ export default defineConfig({
|
|
|
657
657
|
|
|
658
658
|
Every game must include 4 images in the `assets/` directory. These are validated and packaged by the `pack` command.
|
|
659
659
|
|
|
660
|
-
| Image | Aspect Ratio |
|
|
661
|
-
|
|
662
|
-
| `icon.png` | 1:1 |
|
|
663
|
-
| `banner.png` | 16:9 |
|
|
664
|
-
| `cover.png` | 21:9 |
|
|
665
|
-
| `splash.png` | 9:21 |
|
|
660
|
+
| Image | Aspect Ratio | Recommended Size | Purpose |
|
|
661
|
+
|-------|-------------|-----------------|---------|
|
|
662
|
+
| `icon.png` | 1:1 | 512x512 | Game list icon |
|
|
663
|
+
| `banner.png` or `.webp` | 16:9 | 1280x720 | Lobby banner |
|
|
664
|
+
| `cover.png` or `.webp` | 21:9 | 1260x540 | Store/featured cover |
|
|
665
|
+
| `splash.png` or `.webp` | 9:21 | 1080x2520 | Loading/splash screen |
|
|
666
666
|
|
|
667
667
|
**Rules:**
|
|
668
|
-
- **Formats**: PNG or WebP only
|
|
668
|
+
- **Formats**: PNG or WebP only. Recommendation: use PNG for icon (small, sharp edges), WebP for banner/cover/splash (photo-like content, 60-80% smaller than PNG)
|
|
669
669
|
- **Aspect ratio**: Must match exactly (1% tolerance)
|
|
670
|
-
- **
|
|
671
|
-
- **File size**: Warning if any image exceeds 2MB
|
|
672
|
-
- **Paths**: Referenced in `GameConfig.assets` as relative paths from the project root
|
|
670
|
+
- **Dimensions**: Must meet or exceed the recommended size. Exact match preferred; larger with correct ratio also accepted
|
|
671
|
+
- **File size**: Warning if any image exceeds 2MB (WebP typically avoids this even at splash resolution)
|
|
672
|
+
- **Paths**: Referenced in `GameConfig.assets` as relative paths from the project root (e.g., `"assets/banner.webp"`)
|
|
673
673
|
|
|
674
|
-
The `pack` command reads these images, validates them, and includes them in the zip with canonical names (`icon
|
|
674
|
+
The `pack` command reads these images, validates them, and includes them in the zip with canonical names (`icon`, `banner`, `cover`, `splash`) preserving the original file extension (`.png` or `.webp`).
|
|
675
675
|
|
|
676
676
|
### Custom Game Assets
|
|
677
677
|
|
|
@@ -679,10 +679,10 @@ For assets used inside your game UI (card images, sound effects, fonts, etc.), p
|
|
|
679
679
|
|
|
680
680
|
```
|
|
681
681
|
assets/
|
|
682
|
-
├── icon.png # Platform display images (root level, required)
|
|
683
|
-
├── banner.
|
|
684
|
-
├── cover.
|
|
685
|
-
├── splash.
|
|
682
|
+
├── icon.png # Platform display images (root level, required, .png or .webp)
|
|
683
|
+
├── banner.webp
|
|
684
|
+
├── cover.webp
|
|
685
|
+
├── splash.webp
|
|
686
686
|
├── cards/ # Custom game assets (subdirectories)
|
|
687
687
|
│ ├── king.png
|
|
688
688
|
│ └── queen.png
|
|
@@ -724,7 +724,7 @@ export default function GameRenderer({ platform, state }: GameRendererProps) {
|
|
|
724
724
|
| Approach | When to Use | How |
|
|
725
725
|
|----------|-------------|-----|
|
|
726
726
|
| **Inline in bundle** | Tiny assets (< 4KB) | Vite automatically inlines as data URLs |
|
|
727
|
-
| **CSS/SVG** | UI elements, icons |
|
|
727
|
+
| **CSS/SVG** | UI elements, icons | Inline styles, `<style>` injection, or inline SVG components |
|
|
728
728
|
| **Emoji/Unicode** | Simple visual indicators | Unicode characters directly in JSX |
|
|
729
729
|
|
|
730
730
|
> **Tip:** Use `platform.getAssetUrl()` for assets 100KB+ instead of inlining them into the bundle.
|
|
@@ -822,30 +822,114 @@ interface PlayerState {
|
|
|
822
822
|
|
|
823
823
|
### Renderer Rules
|
|
824
824
|
1. **React functional component**: Use hooks, not class components.
|
|
825
|
-
2. **Tailwind CSS
|
|
825
|
+
2. **Inline styles + `<style>` injection**: Do NOT use Tailwind CSS (see "Renderer Styling Guide" below). Use inline styles with CSS variables for layout and theming. Use `<style>` injection for animations and pseudo-classes.
|
|
826
826
|
3. **Mobile-first**: Design for phone screens (375px width). The platform is a PWA.
|
|
827
827
|
4. **No direct socket access**: Only use `platform.send()` and `platform.on()`.
|
|
828
828
|
5. **Chinese UI text**: The platform targets Chinese-speaking users.
|
|
829
829
|
6. **Responsive touch targets**: Buttons should be at least 44x44px for mobile.
|
|
830
830
|
|
|
831
|
+
### Renderer Styling Guide
|
|
832
|
+
|
|
833
|
+
**Do NOT use Tailwind CSS in game renderers.** The production platform pre-compiles Tailwind at build time and only scans the platform's own source code — game bundles are loaded dynamically at runtime, so Tailwind utility classes (especially arbitrary values like `w-[280px]`, `text-[18px]`) will silently fail in production even though they work in the dev-kit.
|
|
834
|
+
|
|
835
|
+
Use **inline styles** as the primary styling method, with **`<style>` injection** for features that inline styles can't express (animations, pseudo-classes, hover states).
|
|
836
|
+
|
|
837
|
+
#### Inline styles (primary)
|
|
838
|
+
|
|
839
|
+
```tsx
|
|
840
|
+
// ✅ Use inline styles with CSS variables
|
|
841
|
+
<div style={{ width: 280, height: 60, fontSize: 18, color: "var(--text-primary)" }}>
|
|
842
|
+
|
|
843
|
+
// ❌ Do NOT use Tailwind classes
|
|
844
|
+
<div className="w-[280px] h-[60px] text-[18px] text-text-primary">
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
#### `<style>` injection (for animations and pseudo-classes)
|
|
848
|
+
|
|
849
|
+
```tsx
|
|
850
|
+
const GameStyles = () => (
|
|
851
|
+
<style>{`
|
|
852
|
+
@keyframes card-flip {
|
|
853
|
+
0% { transform: rotateY(0deg); }
|
|
854
|
+
50% { transform: rotateY(90deg); scale: 1.1; }
|
|
855
|
+
100% { transform: rotateY(180deg); }
|
|
856
|
+
}
|
|
857
|
+
.my-game-card-flip { animation: card-flip 0.6s ease-in-out; }
|
|
858
|
+
.my-game-btn:disabled { opacity: 0.4; }
|
|
859
|
+
.my-game-input:focus { outline: none; border-color: var(--accent-primary); }
|
|
860
|
+
`}</style>
|
|
861
|
+
);
|
|
862
|
+
|
|
863
|
+
export default function GameRenderer({ platform, state }: GameRendererProps) {
|
|
864
|
+
return (
|
|
865
|
+
<div>
|
|
866
|
+
<GameStyles />
|
|
867
|
+
<div className="my-game-card-flip" style={{ width: 120, height: 180 }}>
|
|
868
|
+
{/* card content */}
|
|
869
|
+
</div>
|
|
870
|
+
</div>
|
|
871
|
+
);
|
|
872
|
+
}
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
> **Tip:** Prefix your CSS class names with your game name (e.g., `my-game-`) to avoid conflicts when multiple games coexist.
|
|
876
|
+
|
|
877
|
+
#### Why this approach
|
|
878
|
+
|
|
879
|
+
- **Zero dependencies**: No CSS framework needed
|
|
880
|
+
- **Consistent across environments**: Inline styles work identically in dev-kit and production
|
|
881
|
+
- **No conflicts**: Inline styles are naturally isolated; multiple games won't interfere
|
|
882
|
+
- **More flexible animations**: Native CSS keyframes support multi-stage animations, cubic-bezier curves, and staggered delays — more powerful than Tailwind's preset `animate-*` classes
|
|
883
|
+
|
|
831
884
|
### Design Token Reference
|
|
832
885
|
|
|
833
|
-
Use these CSS variables
|
|
834
|
-
|
|
835
|
-
| Purpose | CSS Variable |
|
|
836
|
-
|
|
837
|
-
| Page background | `--bg-primary` | `bg-
|
|
838
|
-
| Card background | `--bg-secondary` | `bg-
|
|
839
|
-
| Elevated surface | `--bg-tertiary` | `bg-
|
|
840
|
-
| Primary accent | `--accent-primary` | `
|
|
841
|
-
| Primary text | `--text-primary` | `text-
|
|
842
|
-
| Secondary text | `--text-secondary` | `text-
|
|
843
|
-
| Muted text | `--text-tertiary` | `text-
|
|
844
|
-
| Border | `--border-default` | `border
|
|
845
|
-
| Success | `--success` | `
|
|
846
|
-
| Error | `--error` | `
|
|
847
|
-
|
|
|
848
|
-
|
|
|
886
|
+
Use these CSS variables in your inline styles for consistent theming:
|
|
887
|
+
|
|
888
|
+
| Purpose | CSS Variable | Inline Style Example |
|
|
889
|
+
|---------|-------------|---------------------|
|
|
890
|
+
| Page background | `--bg-primary` | `background: "var(--bg-primary)"` |
|
|
891
|
+
| Card background | `--bg-secondary` | `background: "var(--bg-secondary)"` |
|
|
892
|
+
| Elevated surface | `--bg-tertiary` | `background: "var(--bg-tertiary)"` |
|
|
893
|
+
| Primary accent | `--accent-primary` | `color: "var(--accent-primary)"` |
|
|
894
|
+
| Primary text | `--text-primary` | `color: "var(--text-primary)"` |
|
|
895
|
+
| Secondary text | `--text-secondary` | `color: "var(--text-secondary)"` |
|
|
896
|
+
| Muted text | `--text-tertiary` | `color: "var(--text-tertiary)"` |
|
|
897
|
+
| Border | `--border-default` | `border: "1px solid var(--border-default)"` |
|
|
898
|
+
| Success | `--success` | `color: "var(--success)"` |
|
|
899
|
+
| Error | `--error` | `color: "var(--error)"` |
|
|
900
|
+
| Body font (sans-serif) | `--font-body` | `fontFamily: "var(--font-body)"` |
|
|
901
|
+
| Serif font | `--font-serif` | `fontFamily: "var(--font-serif)"` |
|
|
902
|
+
| Display font | `--font-display` | `fontFamily: "var(--font-display)"` |
|
|
903
|
+
|
|
904
|
+
### Platform Fonts
|
|
905
|
+
|
|
906
|
+
The platform self-hosts **Noto Sans SC** (sans-serif) and **Noto Serif SC** (serif) via `next/font/google`, available to all games inside the sandbox container.
|
|
907
|
+
|
|
908
|
+
| CSS Variable | Font | Type |
|
|
909
|
+
|---|---|---|
|
|
910
|
+
| `--font-body` | Noto Sans SC | sans-serif (default — inherited automatically) |
|
|
911
|
+
| `--font-serif` | Noto Serif SC | serif |
|
|
912
|
+
| `--font-display` | Comfortaa | display / title |
|
|
913
|
+
|
|
914
|
+
Games inherit `--font-body` (Noto Sans SC) by default — no action needed for sans-serif text.
|
|
915
|
+
|
|
916
|
+
To use the serif font:
|
|
917
|
+
|
|
918
|
+
```tsx
|
|
919
|
+
<p style={{ fontFamily: "var(--font-serif)" }}>衬线体文本</p>
|
|
920
|
+
```
|
|
921
|
+
|
|
922
|
+
**Do NOT reference fonts by name.** The platform uses hashed `font-family` names internally, so literal font names will not match the self-hosted font files:
|
|
923
|
+
|
|
924
|
+
```css
|
|
925
|
+
/* ✅ Works */
|
|
926
|
+
font-family: var(--font-body);
|
|
927
|
+
font-family: var(--font-serif);
|
|
928
|
+
|
|
929
|
+
/* ❌ Does NOT work — won't match the self-hosted font */
|
|
930
|
+
font-family: 'Noto Sans SC', sans-serif;
|
|
931
|
+
font-family: 'Noto Serif SC', serif;
|
|
932
|
+
```
|
|
849
933
|
|
|
850
934
|
## Platform Runtime Constraints
|
|
851
935
|
|
package/dist/interfaces.d.ts
CHANGED
|
@@ -9,13 +9,13 @@ export interface GameState {
|
|
|
9
9
|
data: Record<string, unknown>;
|
|
10
10
|
}
|
|
11
11
|
export interface GameAssets {
|
|
12
|
-
/** 1:1 game list icon (
|
|
12
|
+
/** 1:1 game list icon (512x512+ recommended, .png or .webp) */
|
|
13
13
|
icon: string;
|
|
14
|
-
/** 16:9 lobby banner */
|
|
14
|
+
/** 16:9 lobby banner (1280x720+ recommended, .png or .webp) */
|
|
15
15
|
banner: string;
|
|
16
|
-
/** 21:9 store/featured cover */
|
|
16
|
+
/** 21:9 store/featured cover (1260x540+ recommended, .png or .webp) */
|
|
17
17
|
cover: string;
|
|
18
|
-
/** 9:21 loading/splash screen */
|
|
18
|
+
/** 9:21 loading/splash screen (1080x2520+ recommended, .png or .webp) */
|
|
19
19
|
splash: string;
|
|
20
20
|
}
|
|
21
21
|
export interface GameConfig {
|
package/dist/interfaces.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExE,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,UAAU;IACzB
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExE,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,UAAU;IACzB,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACtE,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,SAAS,CAAC;IAChF;;;;;;;;;OASG;IACH,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC;IACtC,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,CAAC;IACxC,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;CACvE;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;CAC3B"}
|
package/package.json
CHANGED