@mpgd/cli 0.9.0 → 0.10.1
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/dist/game-acceptance.d.ts +14 -0
- package/dist/game-acceptance.js +318 -5
- package/dist/gameplay-e2e.d.ts +121 -0
- package/dist/gameplay-e2e.js +684 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +57 -3
- package/package.json +11 -11
- package/templates/phaser-game/README.md +14 -9
- package/templates/phaser-game/agent/acceptance.md +13 -7
- package/templates/phaser-game/agent/game-manifest.json +1 -1
- package/templates/phaser-game/apps/target-devvit/README.md +18 -4
- package/templates/phaser-game/apps/target-devvit/src/server/index.ts +4 -223
- package/templates/phaser-game/apps/target-devvit/src/server/postOperationStore.ts +2 -2
- package/templates/phaser-game/mpgd.game.json +42 -0
- package/templates/phaser-game/src/main.ts +2 -0
- package/templates/phaser-game/src/platform/devvitEntrypoint.ts +104 -29
- package/templates/phaser-game/src/platform/devvitInlineMode.css +133 -0
- package/templates/phaser-game/src/runtime/createGame.ts +6 -0
- package/templates/phaser-game/src/platform/devvitInlinePreview.css +0 -75
|
@@ -1,57 +1,132 @@
|
|
|
1
1
|
import {
|
|
2
2
|
requestDevvitExpandedMode,
|
|
3
|
-
|
|
3
|
+
startDevvitWebView,
|
|
4
|
+
type DevvitInlineModeContext,
|
|
4
5
|
} from '@mpgd/adapter-devvit/web';
|
|
5
6
|
|
|
6
|
-
await
|
|
7
|
-
async
|
|
8
|
-
await import('./
|
|
9
|
-
|
|
7
|
+
await startDevvitWebView({
|
|
8
|
+
async mountInlineMode(context) {
|
|
9
|
+
await import('./devvitInlineMode.css');
|
|
10
|
+
renderInlineLaunchScreen(context);
|
|
10
11
|
},
|
|
11
|
-
async
|
|
12
|
+
async loadGameplay() {
|
|
12
13
|
await import('../main');
|
|
13
14
|
},
|
|
14
15
|
onModeUnavailable(error) {
|
|
15
16
|
if (!(error instanceof ReferenceError)) {
|
|
16
|
-
console.warn('[devvit] web view mode unavailable; loading
|
|
17
|
+
console.warn('[devvit] web view mode unavailable; loading gameplay.', error);
|
|
17
18
|
}
|
|
18
19
|
},
|
|
19
20
|
});
|
|
20
21
|
|
|
21
|
-
function
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
function renderInlineLaunchScreen(
|
|
23
|
+
context: DevvitInlineModeContext,
|
|
24
|
+
errorMessage?: string,
|
|
25
|
+
): void {
|
|
26
|
+
const launchScreen = document.createElement('main');
|
|
27
|
+
launchScreen.className = 'devvit-launch-screen';
|
|
24
28
|
|
|
25
29
|
const eyebrow = document.createElement('p');
|
|
26
|
-
eyebrow.className = 'devvit-
|
|
27
|
-
eyebrow.textContent = '
|
|
30
|
+
eyebrow.className = 'devvit-launch-screen__eyebrow';
|
|
31
|
+
eyebrow.textContent = 'Inline mode';
|
|
28
32
|
|
|
29
33
|
const title = document.createElement('h1');
|
|
30
34
|
title.textContent = '__GAME_TITLE__';
|
|
31
35
|
|
|
32
36
|
const description = document.createElement('p');
|
|
33
|
-
description.className = 'devvit-
|
|
34
|
-
description.textContent = '
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
37
|
+
description.className = 'devvit-launch-screen__description';
|
|
38
|
+
description.textContent = 'Play directly in the post or open expanded mode.';
|
|
39
|
+
|
|
40
|
+
const actions = document.createElement('div');
|
|
41
|
+
actions.className = 'devvit-launch-screen__actions';
|
|
42
|
+
|
|
43
|
+
const playInlineButton = document.createElement('button');
|
|
44
|
+
playInlineButton.className = 'devvit-launch-screen__button';
|
|
45
|
+
playInlineButton.type = 'button';
|
|
46
|
+
playInlineButton.textContent = 'Play here';
|
|
47
|
+
|
|
48
|
+
const expandButton = document.createElement('button');
|
|
49
|
+
expandButton.className =
|
|
50
|
+
'devvit-launch-screen__button devvit-launch-screen__button--secondary';
|
|
51
|
+
expandButton.type = 'button';
|
|
52
|
+
expandButton.textContent = 'Open expanded mode';
|
|
53
|
+
|
|
54
|
+
const status = document.createElement('p');
|
|
55
|
+
status.className = 'devvit-launch-screen__status';
|
|
56
|
+
status.setAttribute('aria-live', 'polite');
|
|
57
|
+
status.textContent = errorMessage ?? '';
|
|
58
|
+
|
|
59
|
+
playInlineButton.addEventListener('click', () => {
|
|
60
|
+
setBusy(true, 'Loading gameplay…');
|
|
61
|
+
const loading = mountGameplayDocument();
|
|
62
|
+
|
|
63
|
+
void context.startGameplay()
|
|
64
|
+
.then(() => {
|
|
65
|
+
loading.remove();
|
|
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
|
+
});
|
|
46
71
|
});
|
|
72
|
+
expandButton.addEventListener('click', (event) => {
|
|
73
|
+
setBusy(true, 'Opening expanded mode…');
|
|
74
|
+
|
|
75
|
+
void requestDevvitExpandedMode(event, 'game')
|
|
76
|
+
.then(() => {
|
|
77
|
+
setBusy(false, '');
|
|
78
|
+
})
|
|
79
|
+
.catch((error: unknown) => {
|
|
80
|
+
console.error('[devvit] expanded mode request failed.', error);
|
|
81
|
+
setBusy(false, 'Expanded mode is unavailable. Try again.');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
actions.append(playInlineButton, expandButton);
|
|
86
|
+
launchScreen.append(eyebrow, title, description, actions, status);
|
|
87
|
+
const body = requireDocumentBody();
|
|
88
|
+
|
|
89
|
+
body.classList.remove('devvit-inline-mode-gameplay');
|
|
90
|
+
body.classList.add('devvit-inline-mode-host');
|
|
91
|
+
delete body.dataset.mpgdPreserveBrowserTouchGestures;
|
|
92
|
+
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
|
+
}
|
|
47
123
|
|
|
48
|
-
|
|
124
|
+
function requireDocumentBody(): HTMLElement {
|
|
49
125
|
const body = document.body;
|
|
50
126
|
|
|
51
127
|
if (body === null) {
|
|
52
|
-
throw new Error('Devvit inline
|
|
128
|
+
throw new Error('Devvit inline mode requires a document body.');
|
|
53
129
|
}
|
|
54
130
|
|
|
55
|
-
body
|
|
56
|
-
body.replaceChildren(preview);
|
|
131
|
+
return body;
|
|
57
132
|
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
body.devvit-inline-mode-host {
|
|
2
|
+
min-width: 320px;
|
|
3
|
+
min-height: 100vh;
|
|
4
|
+
margin: 0;
|
|
5
|
+
background: #0f172a;
|
|
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;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.devvit-inline-gameplay-loading {
|
|
23
|
+
position: fixed;
|
|
24
|
+
z-index: 1;
|
|
25
|
+
inset: 0;
|
|
26
|
+
display: grid;
|
|
27
|
+
place-items: center;
|
|
28
|
+
margin: 0;
|
|
29
|
+
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
|
+
}
|
|
34
|
+
|
|
35
|
+
.devvit-launch-screen,
|
|
36
|
+
.devvit-launch-screen * {
|
|
37
|
+
box-sizing: border-box;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.devvit-launch-screen {
|
|
41
|
+
min-height: 100vh;
|
|
42
|
+
display: grid;
|
|
43
|
+
place-content: center;
|
|
44
|
+
justify-items: start;
|
|
45
|
+
gap: 0.75rem;
|
|
46
|
+
padding: clamp(1.25rem, 5vw, 3rem);
|
|
47
|
+
background:
|
|
48
|
+
radial-gradient(circle at 85% 15%, rgb(56 189 248 / 0.2), transparent 38%),
|
|
49
|
+
linear-gradient(145deg, #0f172a, #172554);
|
|
50
|
+
color: #f8fafc;
|
|
51
|
+
font-family: Inter, ui-sans-serif, system-ui, sans-serif;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.devvit-launch-screen__eyebrow,
|
|
55
|
+
.devvit-launch-screen__description,
|
|
56
|
+
.devvit-launch-screen__status,
|
|
57
|
+
.devvit-launch-screen h1 {
|
|
58
|
+
margin: 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.devvit-launch-screen__eyebrow {
|
|
62
|
+
color: #7dd3fc;
|
|
63
|
+
font-size: 0.75rem;
|
|
64
|
+
font-weight: 700;
|
|
65
|
+
letter-spacing: 0.12em;
|
|
66
|
+
text-transform: uppercase;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.devvit-launch-screen h1 {
|
|
70
|
+
max-width: 18ch;
|
|
71
|
+
font-size: clamp(2rem, 9vw, 4.5rem);
|
|
72
|
+
line-height: 0.95;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.devvit-launch-screen__description {
|
|
76
|
+
max-width: 36rem;
|
|
77
|
+
color: #cbd5e1;
|
|
78
|
+
line-height: 1.5;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.devvit-launch-screen__actions {
|
|
82
|
+
display: flex;
|
|
83
|
+
flex-wrap: wrap;
|
|
84
|
+
gap: 0.75rem;
|
|
85
|
+
margin-top: 0.5rem;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.devvit-launch-screen__button {
|
|
89
|
+
min-height: 2.75rem;
|
|
90
|
+
padding: 0.65rem 1.25rem;
|
|
91
|
+
border: 1px solid transparent;
|
|
92
|
+
border-radius: 999px;
|
|
93
|
+
color: #082f49;
|
|
94
|
+
background: #7dd3fc;
|
|
95
|
+
font: inherit;
|
|
96
|
+
font-weight: 800;
|
|
97
|
+
cursor: pointer;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.devvit-launch-screen__button--secondary {
|
|
101
|
+
border-color: #7dd3fc;
|
|
102
|
+
color: #e0f2fe;
|
|
103
|
+
background: rgb(15 23 42 / 0.64);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.devvit-launch-screen__button:disabled {
|
|
107
|
+
cursor: wait;
|
|
108
|
+
opacity: 0.65;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.devvit-launch-screen__button:focus-visible {
|
|
112
|
+
outline: 3px solid #f8fafc;
|
|
113
|
+
outline-offset: 3px;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.devvit-launch-screen__status {
|
|
117
|
+
min-height: 1.5em;
|
|
118
|
+
color: #fda4af;
|
|
119
|
+
font-size: 0.875rem;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@media (hover: hover) {
|
|
123
|
+
.devvit-launch-screen__button:not(:disabled):hover {
|
|
124
|
+
filter: brightness(1.1);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@media (max-width: 420px) {
|
|
129
|
+
.devvit-launch-screen__actions,
|
|
130
|
+
.devvit-launch-screen__button {
|
|
131
|
+
width: 100%;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -7,6 +7,7 @@ import { starterContextKey, type StarterContext } from './gameContext';
|
|
|
7
7
|
|
|
8
8
|
export function createStarterGame(input: {
|
|
9
9
|
readonly mountId: string;
|
|
10
|
+
readonly preserveBrowserTouchGestures?: boolean;
|
|
10
11
|
readonly context: StarterContext;
|
|
11
12
|
}): Phaser.Game {
|
|
12
13
|
const game = new Phaser.Game({
|
|
@@ -15,6 +16,11 @@ export function createStarterGame(input: {
|
|
|
15
16
|
width: 960,
|
|
16
17
|
height: 540,
|
|
17
18
|
backgroundColor: '#07111f',
|
|
19
|
+
input: {
|
|
20
|
+
touch: {
|
|
21
|
+
capture: input.preserveBrowserTouchGestures !== true,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
18
24
|
scale: {
|
|
19
25
|
mode: Phaser.Scale.FIT,
|
|
20
26
|
autoCenter: Phaser.Scale.CENTER_BOTH,
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
body.devvit-preview-host {
|
|
2
|
-
min-width: 320px;
|
|
3
|
-
min-height: 100vh;
|
|
4
|
-
margin: 0;
|
|
5
|
-
background: #0f172a;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
.devvit-preview,
|
|
9
|
-
.devvit-preview * {
|
|
10
|
-
box-sizing: border-box;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
.devvit-preview {
|
|
14
|
-
min-height: 100vh;
|
|
15
|
-
display: grid;
|
|
16
|
-
place-content: center;
|
|
17
|
-
justify-items: start;
|
|
18
|
-
gap: 0.75rem;
|
|
19
|
-
padding: clamp(1.25rem, 5vw, 3rem);
|
|
20
|
-
background:
|
|
21
|
-
radial-gradient(circle at 85% 15%, rgb(56 189 248 / 0.2), transparent 38%),
|
|
22
|
-
linear-gradient(145deg, #0f172a, #172554);
|
|
23
|
-
color: #f8fafc;
|
|
24
|
-
font-family: Inter, ui-sans-serif, system-ui, sans-serif;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.devvit-preview__eyebrow,
|
|
28
|
-
.devvit-preview__description,
|
|
29
|
-
.devvit-preview h1 {
|
|
30
|
-
margin: 0;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.devvit-preview__eyebrow {
|
|
34
|
-
color: #7dd3fc;
|
|
35
|
-
font-size: 0.75rem;
|
|
36
|
-
font-weight: 700;
|
|
37
|
-
letter-spacing: 0.12em;
|
|
38
|
-
text-transform: uppercase;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.devvit-preview h1 {
|
|
42
|
-
max-width: 18ch;
|
|
43
|
-
font-size: clamp(2rem, 9vw, 4.5rem);
|
|
44
|
-
line-height: 0.95;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.devvit-preview__description {
|
|
48
|
-
max-width: 36rem;
|
|
49
|
-
color: #cbd5e1;
|
|
50
|
-
line-height: 1.5;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
.devvit-preview__button {
|
|
54
|
-
min-height: 2.75rem;
|
|
55
|
-
margin-top: 0.5rem;
|
|
56
|
-
padding: 0.65rem 1.25rem;
|
|
57
|
-
border: 0;
|
|
58
|
-
border-radius: 999px;
|
|
59
|
-
color: #082f49;
|
|
60
|
-
background: #7dd3fc;
|
|
61
|
-
font: inherit;
|
|
62
|
-
font-weight: 800;
|
|
63
|
-
cursor: pointer;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
.devvit-preview__button:focus-visible {
|
|
67
|
-
outline: 3px solid #f8fafc;
|
|
68
|
-
outline-offset: 3px;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
@media (hover: hover) {
|
|
72
|
-
.devvit-preview__button:hover {
|
|
73
|
-
filter: brightness(1.1);
|
|
74
|
-
}
|
|
75
|
-
}
|