@mpgd/cli 0.24.0 → 0.25.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 +8 -8
- package/templates/phaser-game/README.md +20 -8
- package/templates/phaser-game/agent/acceptance.md +3 -3
- package/templates/phaser-game/apps/target-ait/src/main.ts +2 -0
- package/templates/phaser-game/apps/target-devvit/README.md +9 -5
- package/templates/phaser-game/apps/target-devvit/package.json +4 -4
- package/templates/phaser-game/apps/target-devvit/vite.config.ts +2 -2
- package/templates/phaser-game/src/platform/devvitEntrypoint.ts +46 -69
- package/templates/phaser-game/src/platform/devvitInlineMode.css +46 -40
- package/templates/phaser-game/vite.shared.ts +14 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mpgd/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "Gunshi CLI for mpgd-kit starter generation and target workflow orchestration.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -52,19 +52,19 @@
|
|
|
52
52
|
"@types/node": "^24.0.0",
|
|
53
53
|
"ttsc": "0.18.4",
|
|
54
54
|
"typescript": "7.0.2",
|
|
55
|
-
"@mpgd/adapter-ait": "0.
|
|
56
|
-
"@mpgd/adapter-browser": "0.7.1",
|
|
55
|
+
"@mpgd/adapter-ait": "0.11.0",
|
|
57
56
|
"@mpgd/adapter-capacitor": "0.4.7",
|
|
58
|
-
"@mpgd/adapter-devvit": "0.9.
|
|
57
|
+
"@mpgd/adapter-devvit": "0.9.3",
|
|
58
|
+
"@mpgd/adapter-browser": "0.7.1",
|
|
59
59
|
"@mpgd/adapter-verse8": "0.3.1",
|
|
60
60
|
"@mpgd/analytics": "0.3.10",
|
|
61
61
|
"@mpgd/bridge": "0.9.0",
|
|
62
|
-
"@mpgd/catalog": "0.7.0",
|
|
63
62
|
"@mpgd/game-services": "0.12.1",
|
|
64
|
-
"@mpgd/
|
|
65
|
-
"@mpgd/platform": "0.10.0",
|
|
63
|
+
"@mpgd/catalog": "0.7.0",
|
|
66
64
|
"@mpgd/i18n": "0.5.6",
|
|
67
|
-
"@mpgd/
|
|
65
|
+
"@mpgd/phaser-assets": "0.4.1",
|
|
66
|
+
"@mpgd/target-config": "0.13.0",
|
|
67
|
+
"@mpgd/platform": "0.10.0"
|
|
68
68
|
},
|
|
69
69
|
"main": "./dist/index.js",
|
|
70
70
|
"types": "./dist/index.d.ts",
|
|
@@ -231,12 +231,16 @@ The generated `devvit.json` app name is a Devvit-safe slug derived from the game
|
|
|
231
231
|
directory name; edit it before `devvit:init` if you need a different Reddit app
|
|
232
232
|
name.
|
|
233
233
|
|
|
234
|
-
The default post entry builds a
|
|
235
|
-
importing Phaser
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
234
|
+
The default post entry builds a fixed, non-scrolling inline preview without
|
|
235
|
+
importing Phaser. Play full screen requests the separate `game` entrypoint,
|
|
236
|
+
whose `game.html` document starts the Phaser bundle directly. Keep these
|
|
237
|
+
physical entries separate so feed cards preserve Reddit-native gestures and do
|
|
238
|
+
not create scroll traps.
|
|
239
|
+
|
|
240
|
+
Inline gameplay remains an explicit opt-in through `startDevvitWebView`. Use it
|
|
241
|
+
only when the game interaction is tap/click based and the complete inline
|
|
242
|
+
surface has been reviewed against current Reddit requirements. Generated games
|
|
243
|
+
use `startDevvitPreviewWebView` by default.
|
|
240
244
|
|
|
241
245
|
First-time Devvit setup:
|
|
242
246
|
|
|
@@ -312,8 +316,16 @@ Apps in Toss navigation chrome is target-owned. Configure the `ait` target's
|
|
|
312
316
|
`navigationBar` in `mpgd.targets.json`; `mpgd target build ait` validates the
|
|
313
317
|
supported appearance options and forwards them to `apps-in-toss.config.ts` at
|
|
314
318
|
build time. The Phaser starter uses a transparent dark navigation bar without
|
|
315
|
-
back, home, title, or app-icon chrome so game content can continue underneath
|
|
316
|
-
|
|
319
|
+
back, home, title, or app-icon chrome so game content can continue underneath
|
|
320
|
+
it. The wrapper installs `installAitSafeAreaCssVariables()` before the game
|
|
321
|
+
mount, mirrors the official `SafeArea.get()` and `SafeArea.subscribe()` values
|
|
322
|
+
into `--mpgd-safe-area-*`, and exposes
|
|
323
|
+
`--mpgd-ait-navigation-content-top` for a full-width HUD below the native
|
|
324
|
+
controls. CSS `env(safe-area-inset-*)` remains the local and older-host
|
|
325
|
+
fallback. Custom wrappers should import the installer from
|
|
326
|
+
`@mpgd/adapter-ait/safe-area`; keep SDK imports out of Phaser scenes.
|
|
327
|
+
The default 52px navigation band and 10px edge gap can be overridden through
|
|
328
|
+
the installer options when a custom host treatment has measured geometry.
|
|
317
329
|
|
|
318
330
|
During the SDK 3 origin transition, allow all four exact origins on every API
|
|
319
331
|
called by the mini-app:
|
|
@@ -32,9 +32,9 @@ continue to expose game-facing behavior through `PlatformGateway`. The Devvit
|
|
|
32
32
|
app root is game-owned in `apps/target-devvit`; run `pnpm devvit:init` once
|
|
33
33
|
after login before upload or playtest.
|
|
34
34
|
Verify the default post entry renders a lightweight inline mode launch screen,
|
|
35
|
-
|
|
36
|
-
separate expanded mode Phaser document. Inline gameplay
|
|
37
|
-
only and must
|
|
35
|
+
does not load Phaser or create a scroll container, and Play full screen opens
|
|
36
|
+
the separate expanded mode Phaser document. Inline gameplay remains available
|
|
37
|
+
only as an explicit adapter opt-in and must preserve Reddit-native gestures.
|
|
38
38
|
|
|
39
39
|
<!-- mpgd:microsoft-store:start -->
|
|
40
40
|
For Microsoft Store changes, keep the first pass as a PWA/web target that uses
|
|
@@ -2,6 +2,7 @@ import './styles.css';
|
|
|
2
2
|
|
|
3
3
|
import type { AitAdPlacementType } from '@mpgd/adapter-ait/ad-config';
|
|
4
4
|
import { installAitHostBridge, type InstallAitHostBridgeOptions } from '@mpgd/adapter-ait/host';
|
|
5
|
+
import { installAitSafeAreaCssVariables } from '@mpgd/adapter-ait/safe-area';
|
|
5
6
|
import { mountAitGameBundle } from '@mpgd/adapter-ait/wrapper';
|
|
6
7
|
|
|
7
8
|
declare const __MPGD_AIT_APP_NAME__: string;
|
|
@@ -10,6 +11,7 @@ declare const __MPGD_AIT_AD_PLACEMENT_TYPES__: Readonly<
|
|
|
10
11
|
Record<string, AitAdPlacementType>
|
|
11
12
|
>;
|
|
12
13
|
|
|
14
|
+
installAitSafeAreaCssVariables();
|
|
13
15
|
installAitHostBridge({
|
|
14
16
|
appName: __MPGD_AIT_APP_NAME__,
|
|
15
17
|
adGroupIds: __MPGD_AIT_AD_GROUP_IDS__,
|
|
@@ -41,11 +41,15 @@ replace the `devvit.json` scheduler endpoint and should not use process-local
|
|
|
41
41
|
memory when delivery must cross instances. The generated target exposes only
|
|
42
42
|
the oRPC bridge route; the former JSON compatibility route is not generated.
|
|
43
43
|
|
|
44
|
-
The default post entry uses `index.html` for a
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
The default post entry uses `index.html` for a fixed, non-scrolling preview.
|
|
45
|
+
Play full screen requests the `game` entrypoint, which loads Phaser from the
|
|
46
|
+
separate `game.html` document. Keep preview UI free of game runtime imports so
|
|
47
|
+
the post cannot trap feed scrolling.
|
|
48
|
+
|
|
49
|
+
Games that intentionally support inline gameplay can opt in through
|
|
50
|
+
`startDevvitWebView`; the generated default uses `startDevvitPreviewWebView`.
|
|
51
|
+
An opt-in inline surface must remain tap/click based and preserve Reddit-native
|
|
52
|
+
gestures across its complete gameplay flow.
|
|
49
53
|
|
|
50
54
|
The generated bridge does not advertise or accept a generic platform
|
|
51
55
|
leaderboard. Devvit ranking should be owned by a server completion handler that
|
|
@@ -19,17 +19,17 @@
|
|
|
19
19
|
"fix": "ttsc fix"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@devvit/web": "0.
|
|
22
|
+
"@devvit/web": "0.14.1",
|
|
23
23
|
"@mpgd/adapter-devvit": "__MPGD_DEPENDENCY_VERSION_ADAPTER_DEVVIT__",
|
|
24
24
|
"@mpgd/bridge": "__MPGD_DEPENDENCY_VERSION_BRIDGE__"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@devvit/start": "0.
|
|
27
|
+
"@devvit/start": "0.14.1",
|
|
28
28
|
"@ttsc/unplugin": "0.18.4",
|
|
29
29
|
"@types/node": "^24.0.0",
|
|
30
|
-
"devvit": "0.
|
|
30
|
+
"devvit": "0.14.1",
|
|
31
31
|
"ttsc": "0.18.4",
|
|
32
32
|
"typescript": "7.0.2",
|
|
33
|
-
"vite": "
|
|
33
|
+
"vite": "7.3.6"
|
|
34
34
|
}
|
|
35
35
|
}
|
|
@@ -2,7 +2,7 @@ import { resolve } from 'node:path';
|
|
|
2
2
|
import { fileURLToPath } from 'node:url';
|
|
3
3
|
|
|
4
4
|
import { devvit } from '@devvit/start/vite';
|
|
5
|
-
import { defineConfig } from 'vite';
|
|
5
|
+
import { defineConfig, type PluginOption } from 'vite';
|
|
6
6
|
|
|
7
7
|
import { createGameViteSharedConfig } from '../../vite.shared';
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@ const wrapperRoot = fileURLToPath(new URL('.', import.meta.url));
|
|
|
10
10
|
const gameRoot = resolve(wrapperRoot, '../..');
|
|
11
11
|
|
|
12
12
|
export default defineConfig(({ mode }) => {
|
|
13
|
-
const shared = createGameViteSharedConfig({
|
|
13
|
+
const shared = createGameViteSharedConfig<PluginOption>({
|
|
14
14
|
appTarget: 'reddit',
|
|
15
15
|
configTarget: 'reddit',
|
|
16
16
|
gameRoot,
|
|
@@ -1,28 +1,26 @@
|
|
|
1
1
|
import {
|
|
2
2
|
requestDevvitExpandedMode,
|
|
3
|
-
|
|
4
|
-
type DevvitInlineModeContext,
|
|
3
|
+
startDevvitPreviewWebView,
|
|
5
4
|
} from '@mpgd/adapter-devvit/web';
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
const expandedRequestRecoveryMs = 8_000;
|
|
7
|
+
|
|
8
|
+
await startDevvitPreviewWebView({
|
|
9
|
+
async mountInlinePreview() {
|
|
9
10
|
await import('./devvitInlineMode.css');
|
|
10
|
-
renderInlineLaunchScreen(
|
|
11
|
+
renderInlineLaunchScreen();
|
|
11
12
|
},
|
|
12
|
-
async
|
|
13
|
+
async loadExpandedGame() {
|
|
13
14
|
await import('../main');
|
|
14
15
|
},
|
|
15
16
|
onModeUnavailable(error) {
|
|
16
17
|
if (!(error instanceof ReferenceError)) {
|
|
17
|
-
console.warn('[devvit] web view mode unavailable; loading gameplay.', error);
|
|
18
|
+
console.warn('[devvit] web view mode unavailable; loading expanded gameplay.', error);
|
|
18
19
|
}
|
|
19
20
|
},
|
|
20
21
|
});
|
|
21
22
|
|
|
22
|
-
function renderInlineLaunchScreen(
|
|
23
|
-
context: DevvitInlineModeContext,
|
|
24
|
-
errorMessage?: string,
|
|
25
|
-
): void {
|
|
23
|
+
function renderInlineLaunchScreen(): void {
|
|
26
24
|
const launchScreen = document.createElement('main');
|
|
27
25
|
launchScreen.className = 'devvit-launch-screen';
|
|
28
26
|
|
|
@@ -35,90 +33,69 @@ function renderInlineLaunchScreen(
|
|
|
35
33
|
|
|
36
34
|
const description = document.createElement('p');
|
|
37
35
|
description.className = 'devvit-launch-screen__description';
|
|
38
|
-
description.textContent = '
|
|
36
|
+
description.textContent = 'Open the full game without interrupting your Reddit feed.';
|
|
39
37
|
|
|
40
38
|
const actions = document.createElement('div');
|
|
41
39
|
actions.className = 'devvit-launch-screen__actions';
|
|
42
40
|
|
|
43
|
-
const playInlineButton = document.createElement('button');
|
|
44
|
-
playInlineButton.className = 'devvit-launch-screen__button';
|
|
45
|
-
playInlineButton.type = 'button';
|
|
46
|
-
playInlineButton.textContent = 'Play here';
|
|
47
|
-
|
|
48
41
|
const expandButton = document.createElement('button');
|
|
49
|
-
expandButton.className =
|
|
50
|
-
'devvit-launch-screen__button devvit-launch-screen__button--secondary';
|
|
42
|
+
expandButton.className = 'devvit-launch-screen__button';
|
|
51
43
|
expandButton.type = 'button';
|
|
52
|
-
expandButton.textContent = '
|
|
44
|
+
expandButton.textContent = 'Play full screen';
|
|
53
45
|
|
|
54
46
|
const status = document.createElement('p');
|
|
55
47
|
status.className = 'devvit-launch-screen__status';
|
|
56
48
|
status.setAttribute('aria-live', 'polite');
|
|
57
|
-
status.
|
|
49
|
+
status.setAttribute('role', 'status');
|
|
50
|
+
|
|
51
|
+
let nextRequestId = 0;
|
|
52
|
+
let activeRequestId: number | undefined;
|
|
53
|
+
let recoveryTimeout: ReturnType<typeof globalThis.setTimeout> | undefined;
|
|
54
|
+
const recover = (requestId: number, message: string) => {
|
|
55
|
+
if (activeRequestId !== requestId) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
activeRequestId = undefined;
|
|
60
|
+
if (recoveryTimeout !== undefined) {
|
|
61
|
+
globalThis.clearTimeout(recoveryTimeout);
|
|
62
|
+
recoveryTimeout = undefined;
|
|
63
|
+
}
|
|
62
64
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
})
|
|
67
|
-
.catch((error: unknown) => {
|
|
68
|
-
console.error('[devvit] inline mode gameplay failed to load.', error);
|
|
69
|
-
renderInlineLaunchScreen(context, 'Gameplay could not start. Try again.');
|
|
70
|
-
});
|
|
71
|
-
});
|
|
65
|
+
expandButton.disabled = false;
|
|
66
|
+
status.textContent = message;
|
|
67
|
+
};
|
|
72
68
|
expandButton.addEventListener('click', (event) => {
|
|
73
|
-
|
|
69
|
+
const requestId = ++nextRequestId;
|
|
70
|
+
|
|
71
|
+
activeRequestId = requestId;
|
|
72
|
+
expandButton.disabled = true;
|
|
73
|
+
status.textContent = 'Opening full screen…';
|
|
74
|
+
recoveryTimeout = globalThis.setTimeout(() => {
|
|
75
|
+
recover(requestId, 'Full screen did not open. Try again.');
|
|
76
|
+
}, expandedRequestRecoveryMs);
|
|
74
77
|
|
|
75
78
|
void requestDevvitExpandedMode(event, 'game')
|
|
76
|
-
.then(() => {
|
|
77
|
-
setBusy(false, '');
|
|
78
|
-
})
|
|
79
79
|
.catch((error: unknown) => {
|
|
80
80
|
console.error('[devvit] expanded mode request failed.', error);
|
|
81
|
-
|
|
81
|
+
recover(requestId, 'Full screen is unavailable. Try again.');
|
|
82
82
|
});
|
|
83
83
|
});
|
|
84
|
+
const recoverAfterReturn = () => {
|
|
85
|
+
if (activeRequestId !== undefined) {
|
|
86
|
+
recover(activeRequestId, '');
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
globalThis.addEventListener('focus', recoverAfterReturn);
|
|
90
|
+
globalThis.addEventListener('pageshow', recoverAfterReturn);
|
|
84
91
|
|
|
85
|
-
actions.append(
|
|
92
|
+
actions.append(expandButton);
|
|
86
93
|
launchScreen.append(eyebrow, title, description, actions, status);
|
|
87
94
|
const body = requireDocumentBody();
|
|
88
95
|
|
|
89
|
-
body.classList.remove('devvit-inline-mode-gameplay');
|
|
90
96
|
body.classList.add('devvit-inline-mode-host');
|
|
91
97
|
delete body.dataset.mpgdPreserveBrowserTouchGestures;
|
|
92
98
|
body.replaceChildren(launchScreen);
|
|
93
|
-
|
|
94
|
-
function setBusy(busy: boolean, message: string): void {
|
|
95
|
-
playInlineButton.disabled = busy;
|
|
96
|
-
expandButton.disabled = busy;
|
|
97
|
-
status.textContent = message;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function mountGameplayDocument(): HTMLElement {
|
|
102
|
-
const body = requireDocumentBody();
|
|
103
|
-
const app = document.createElement('main');
|
|
104
|
-
const game = document.createElement('div');
|
|
105
|
-
const loading = document.createElement('p');
|
|
106
|
-
|
|
107
|
-
app.id = 'app';
|
|
108
|
-
game.id = 'game';
|
|
109
|
-
loading.className = 'devvit-inline-gameplay-loading';
|
|
110
|
-
loading.setAttribute('aria-live', 'polite');
|
|
111
|
-
loading.setAttribute('role', 'status');
|
|
112
|
-
loading.textContent = 'Loading gameplay…';
|
|
113
|
-
game.append(loading);
|
|
114
|
-
app.append(game);
|
|
115
|
-
|
|
116
|
-
body.classList.remove('devvit-inline-mode-host');
|
|
117
|
-
body.classList.add('devvit-inline-mode-gameplay');
|
|
118
|
-
body.dataset.mpgdPreserveBrowserTouchGestures = 'true';
|
|
119
|
-
body.replaceChildren(app);
|
|
120
|
-
|
|
121
|
-
return loading;
|
|
122
99
|
}
|
|
123
100
|
|
|
124
101
|
function requireDocumentBody(): HTMLElement {
|
|
@@ -1,35 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
html,
|
|
2
|
+
body {
|
|
3
|
+
width: 100%;
|
|
4
|
+
height: 100%;
|
|
4
5
|
margin: 0;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
body.devvit-inline-mode-gameplay {
|
|
9
|
-
overflow-y: auto;
|
|
10
|
-
overscroll-behavior-y: auto;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
body.devvit-inline-mode-gameplay #game {
|
|
14
|
-
position: relative;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
body.devvit-inline-mode-gameplay #game,
|
|
18
|
-
body.devvit-inline-mode-gameplay canvas {
|
|
19
|
-
touch-action: pan-y !important;
|
|
6
|
+
overflow: hidden;
|
|
7
|
+
overscroll-behavior: auto;
|
|
8
|
+
touch-action: pan-y;
|
|
20
9
|
}
|
|
21
10
|
|
|
22
|
-
.devvit-inline-
|
|
23
|
-
position: fixed;
|
|
24
|
-
z-index: 1;
|
|
25
|
-
inset: 0;
|
|
26
|
-
display: grid;
|
|
27
|
-
place-items: center;
|
|
28
|
-
margin: 0;
|
|
11
|
+
body.devvit-inline-mode-host {
|
|
29
12
|
background: #0f172a;
|
|
30
|
-
color: #cbd5e1;
|
|
31
|
-
font: 700 0.875rem/1.5 Inter, ui-sans-serif, system-ui, sans-serif;
|
|
32
|
-
pointer-events: none;
|
|
33
13
|
}
|
|
34
14
|
|
|
35
15
|
.devvit-launch-screen,
|
|
@@ -38,10 +18,14 @@ body.devvit-inline-mode-gameplay canvas {
|
|
|
38
18
|
}
|
|
39
19
|
|
|
40
20
|
.devvit-launch-screen {
|
|
41
|
-
|
|
21
|
+
position: fixed;
|
|
22
|
+
inset: 0;
|
|
23
|
+
width: 100%;
|
|
24
|
+
height: 100dvh;
|
|
25
|
+
overflow: hidden;
|
|
42
26
|
display: grid;
|
|
43
|
-
place-content: center;
|
|
44
|
-
justify-items:
|
|
27
|
+
place-content: safe center;
|
|
28
|
+
justify-items: center;
|
|
45
29
|
gap: 0.75rem;
|
|
46
30
|
padding: clamp(1.25rem, 5vw, 3rem);
|
|
47
31
|
background:
|
|
@@ -49,6 +33,8 @@ body.devvit-inline-mode-gameplay canvas {
|
|
|
49
33
|
linear-gradient(145deg, #0f172a, #172554);
|
|
50
34
|
color: #f8fafc;
|
|
51
35
|
font-family: Inter, ui-sans-serif, system-ui, sans-serif;
|
|
36
|
+
text-align: center;
|
|
37
|
+
touch-action: pan-y;
|
|
52
38
|
}
|
|
53
39
|
|
|
54
40
|
.devvit-launch-screen__eyebrow,
|
|
@@ -67,9 +53,16 @@ body.devvit-inline-mode-gameplay canvas {
|
|
|
67
53
|
}
|
|
68
54
|
|
|
69
55
|
.devvit-launch-screen h1 {
|
|
56
|
+
display: -webkit-box;
|
|
70
57
|
max-width: 18ch;
|
|
58
|
+
max-height: 1.9em;
|
|
59
|
+
overflow: hidden;
|
|
71
60
|
font-size: clamp(2rem, 9vw, 4.5rem);
|
|
72
61
|
line-height: 0.95;
|
|
62
|
+
overflow-wrap: anywhere;
|
|
63
|
+
-webkit-box-orient: vertical;
|
|
64
|
+
-webkit-line-clamp: 2;
|
|
65
|
+
line-clamp: 2;
|
|
73
66
|
}
|
|
74
67
|
|
|
75
68
|
.devvit-launch-screen__description {
|
|
@@ -79,9 +72,8 @@ body.devvit-inline-mode-gameplay canvas {
|
|
|
79
72
|
}
|
|
80
73
|
|
|
81
74
|
.devvit-launch-screen__actions {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
gap: 0.75rem;
|
|
75
|
+
width: min(100%, 22rem);
|
|
76
|
+
display: grid;
|
|
85
77
|
margin-top: 0.5rem;
|
|
86
78
|
}
|
|
87
79
|
|
|
@@ -97,12 +89,6 @@ body.devvit-inline-mode-gameplay canvas {
|
|
|
97
89
|
cursor: pointer;
|
|
98
90
|
}
|
|
99
91
|
|
|
100
|
-
.devvit-launch-screen__button--secondary {
|
|
101
|
-
border-color: #7dd3fc;
|
|
102
|
-
color: #e0f2fe;
|
|
103
|
-
background: rgb(15 23 42 / 0.64);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
92
|
.devvit-launch-screen__button:disabled {
|
|
107
93
|
cursor: wait;
|
|
108
94
|
opacity: 0.65;
|
|
@@ -131,3 +117,23 @@ body.devvit-inline-mode-gameplay canvas {
|
|
|
131
117
|
width: 100%;
|
|
132
118
|
}
|
|
133
119
|
}
|
|
120
|
+
|
|
121
|
+
@media (max-height: 440px) {
|
|
122
|
+
.devvit-launch-screen {
|
|
123
|
+
gap: 0.45rem;
|
|
124
|
+
padding-block: 0.5rem;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.devvit-launch-screen h1 {
|
|
128
|
+
font-size: clamp(1.75rem, 8vw, 2.5rem);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.devvit-launch-screen__description {
|
|
132
|
+
font-size: 0.875rem;
|
|
133
|
+
line-height: 1.3;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.devvit-launch-screen__actions {
|
|
137
|
+
margin-top: 0.2rem;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
|
|
4
4
|
import ttsc from '@ttsc/unplugin/vite';
|
|
5
|
-
import type { PluginOption
|
|
5
|
+
import type { PluginOption } from 'vite';
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
8
|
assertRuntimeTargetConfigMatrix,
|
|
@@ -29,9 +29,19 @@ export interface CreateGameViteSharedConfigInput {
|
|
|
29
29
|
readonly adPlacementsFile?: string;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
/** Vite-major-neutral subset shared by every generated target wrapper. */
|
|
33
|
+
export interface GameViteSharedConfig<SharedPluginOption> {
|
|
34
|
+
readonly base: string;
|
|
35
|
+
readonly plugins: SharedPluginOption[];
|
|
36
|
+
readonly resolve: {
|
|
37
|
+
readonly alias: Record<string, string>;
|
|
38
|
+
};
|
|
39
|
+
readonly define: Record<string, string>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function createGameViteSharedConfig<SharedPluginOption = PluginOption>(
|
|
33
43
|
input: CreateGameViteSharedConfigInput,
|
|
34
|
-
):
|
|
44
|
+
): GameViteSharedConfig<SharedPluginOption> {
|
|
35
45
|
const isProduction = input.mode === 'production';
|
|
36
46
|
const appTarget = input.appTarget ?? process.env.APP_TARGET ?? 'browser';
|
|
37
47
|
const configTarget = input.configTarget ?? process.env.MPGD_CONFIG_TARGET ?? '';
|
|
@@ -56,7 +66,7 @@ export function createGameViteSharedConfig(
|
|
|
56
66
|
ttsc({
|
|
57
67
|
project: input.project,
|
|
58
68
|
plugins: false,
|
|
59
|
-
}) as unknown as
|
|
69
|
+
}) as unknown as SharedPluginOption,
|
|
60
70
|
],
|
|
61
71
|
resolve: {
|
|
62
72
|
alias: {
|