@mpgd/cli 0.4.1 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpgd/cli",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Gunshi CLI for mpgd-kit starter generation and target workflow orchestration.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -52,15 +52,15 @@
52
52
  "@mpgd/adapter-ait": "0.3.3",
53
53
  "@mpgd/adapter-browser": "0.3.2",
54
54
  "@mpgd/adapter-capacitor": "0.3.3",
55
- "@mpgd/analytics": "0.3.2",
56
55
  "@mpgd/adapter-devvit": "0.3.3",
56
+ "@mpgd/analytics": "0.3.2",
57
57
  "@mpgd/bridge": "0.4.0",
58
58
  "@mpgd/catalog": "0.3.2",
59
+ "@mpgd/game-services": "0.3.3",
59
60
  "@mpgd/phaser-assets": "0.4.0",
60
- "@mpgd/platform": "0.3.2",
61
- "@mpgd/target-config": "0.3.4",
62
- "@mpgd/i18n": "0.3.3",
63
- "@mpgd/game-services": "0.3.3"
61
+ "@mpgd/i18n": "0.4.0",
62
+ "@mpgd/target-config": "0.4.0",
63
+ "@mpgd/platform": "0.3.2"
64
64
  },
65
65
  "main": "./dist/index.js",
66
66
  "types": "./dist/index.d.ts",
@@ -84,6 +84,9 @@ const viewport = resolveTargetViewportPlan({
84
84
  height: measured.height,
85
85
  source: measured.source,
86
86
  runtime: runtime.config.runtime,
87
+ orientationPolicy: {
88
+ mode: 'prefer-landscape',
89
+ },
87
90
  });
88
91
  ```
89
92
 
@@ -104,6 +107,15 @@ Orientation is measured from the container: height greater than width is
104
107
  be treated as an embedded webview, so do not assume desktop Reddit always means
105
108
  an expanded game surface.
106
109
 
110
+ Orientation policy is a runtime contract, not a guarantee that every shell can
111
+ hard-lock the device. Use `responsive` when both orientations are playable,
112
+ `prefer-landscape` or `prefer-portrait` when layout guidance should favor one
113
+ orientation, and `lock-landscape` or `lock-portrait` when the game should show a
114
+ soft rotate prompt on mismatch. The generated PWA manifest also declares
115
+ `"orientation": "landscape"` for installed web and Microsoft Store shells; keep
116
+ that manifest value aligned with the runtime policy if you make a portrait-first
117
+ game.
118
+
107
119
  ## Reddit Devvit
108
120
 
109
121
  This starter owns its Devvit app root in `apps/target-devvit`. That directory
@@ -21,3 +21,6 @@ after login before upload or playtest.
21
21
  For Microsoft Store changes, keep the first pass as a PWA/web target that uses
22
22
  the browser adapter. Add a dedicated Store commerce adapter only when wiring
23
23
  Digital Goods API and Payment Request through backend ledger verification.
24
+
25
+ Verify the first screen reports the viewport orientation policy, and treat
26
+ locked orientation modes as soft prompts instead of unsafe WebView hard locks.
@@ -9,6 +9,8 @@ Boundaries:
9
9
  - Purchases, rewarded ad grants, and leaderboard records should go through
10
10
  backend ledger APIs before mutating durable game save state.
11
11
  - Platform SDK imports belong in adapters or target wrappers.
12
+ - Orientation policy should be chosen before adding resize behavior; treat
13
+ locked modes as soft prompts unless a platform adapter supports hard locks.
12
14
 
13
15
  Useful commands:
14
16
 
@@ -25,6 +25,10 @@
25
25
  "id": "runtime.platform.gateway",
26
26
  "owner": "src/platform/installPlatform.ts"
27
27
  },
28
+ {
29
+ "id": "runtime.viewport.orientation-policy",
30
+ "owner": "src/main.ts"
31
+ },
28
32
  {
29
33
  "id": "platform.devvit.app-root",
30
34
  "owner": "apps/target-devvit"
@@ -4,6 +4,8 @@ export type GameMessageKey =
4
4
  | 'title'
5
5
  | 'target'
6
6
  | 'viewport'
7
+ | 'orientationPolicy'
8
+ | 'orientationMismatch'
7
9
  | 'backend'
8
10
  | 'features'
9
11
  | 'featuresNone'
@@ -21,6 +23,8 @@ const messages = {
21
23
  title: '__GAME_TITLE__',
22
24
  target: 'Target: {target}',
23
25
  viewport: 'Viewport: {sizeClass} {orientation} - controls {controls}',
26
+ orientationPolicy: 'Orientation policy: {mode}',
27
+ orientationMismatch: 'Rotate to {orientation} for {mode}',
24
28
  backend: 'Game Services: {mode}',
25
29
  features: 'Features: {features}',
26
30
  featuresNone: 'none',
@@ -37,6 +41,8 @@ const messages = {
37
41
  title: '__GAME_TITLE__',
38
42
  target: '타깃: {target}',
39
43
  viewport: '뷰포트: {sizeClass} {orientation} - 컨트롤 {controls}',
44
+ orientationPolicy: '방향 정책: {mode}',
45
+ orientationMismatch: '{mode}: {orientation} 방향으로 회전',
40
46
  backend: 'Game Services: {mode}',
41
47
  features: '기능: {features}',
42
48
  featuresNone: '없음',
@@ -2,7 +2,10 @@ import './styles.css';
2
2
 
3
3
  import { createAnalyticsReporter, createBufferedAnalyticsSink } from '@mpgd/analytics';
4
4
  import { resolveMpgdLocale, type Locale } from '@mpgd/i18n';
5
- import { resolveTargetViewportPlan } from '@mpgd/target-config';
5
+ import {
6
+ resolveTargetViewportPlan,
7
+ type TargetViewportOrientationPolicy,
8
+ } from '@mpgd/target-config';
6
9
 
7
10
  import { t } from './i18n/messages';
8
11
  import { createClientId } from './runtime/id';
@@ -25,9 +28,13 @@ async function bootstrap(): Promise<void> {
25
28
  const runtimeConfig = detectRuntime();
26
29
  const platform = await installPlatform(runtimeConfig);
27
30
  const runtime = await platform.getTargetRuntime();
31
+ const orientationPolicy = {
32
+ mode: 'prefer-landscape',
33
+ } as const satisfies TargetViewportOrientationPolicy;
28
34
  const viewport = resolveTargetViewportPlan({
29
35
  ...measureGameViewport(),
30
36
  runtime: runtime.config.runtime,
37
+ orientationPolicy,
31
38
  });
32
39
  const player =
33
40
  (await platform.identity.getPlayer()) ?? {
@@ -21,6 +21,16 @@ export class LobbyScene extends Phaser.Scene {
21
21
  .filter((feature) => feature.enabled)
22
22
  .map((feature) => feature.feature)
23
23
  .join(', ') || t(locale, 'featuresNone');
24
+ const orientation = context.viewport.orientation;
25
+ const orientationText =
26
+ orientation.shouldShowRotatePrompt && orientation.preferredOrientation !== undefined
27
+ ? t(locale, 'orientationMismatch', {
28
+ mode: orientation.mode,
29
+ orientation: orientation.preferredOrientation,
30
+ })
31
+ : t(locale, 'orientationPolicy', {
32
+ mode: orientation.mode,
33
+ });
24
34
 
25
35
  this.add
26
36
  .text(480, 106, t(locale, 'title'), {
@@ -61,14 +71,21 @@ export class LobbyScene extends Phaser.Scene {
61
71
  )
62
72
  .setOrigin(0.5);
63
73
  this.add
64
- .text(480, 300, t(locale, 'backend', { mode: context.gameServices.mode }), {
74
+ .text(480, 300, orientationText, {
75
+ color: orientation.shouldShowRotatePrompt ? '#f59e0b' : '#d6dee8',
76
+ fontFamily: 'Arial, sans-serif',
77
+ fontSize: '18px',
78
+ })
79
+ .setOrigin(0.5);
80
+ this.add
81
+ .text(480, 342, t(locale, 'backend', { mode: context.gameServices.mode }), {
65
82
  color: context.gameServices.mode === 'disabled' ? '#f59e0b' : '#2dd4bf',
66
83
  fontFamily: 'Arial, sans-serif',
67
84
  fontSize: '18px',
68
85
  })
69
86
  .setOrigin(0.5);
70
87
  this.add
71
- .text(480, 342, t(locale, 'tapToStart'), {
88
+ .text(480, 384, t(locale, 'tapToStart'), {
72
89
  color: '#ffffff',
73
90
  fontFamily: 'Arial, sans-serif',
74
91
  fontSize: '22px',