@bitmagic/cli 0.1.41 → 0.1.43
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 +23 -1
- package/dist/commands/publish.js +54 -3
- package/dist/commands/publish.js.map +1 -1
- package/dist/editor/asset-detail-panel.d.ts +8 -3
- package/dist/editor/asset-detail-panel.js +31 -25
- package/dist/editor/asset-detail-panel.js.map +1 -1
- package/dist/editor/asset-preview-page.js +15 -6
- package/dist/editor/asset-preview-page.js.map +1 -1
- package/dist/editor/design.d.ts +59 -0
- package/dist/editor/design.js +217 -0
- package/dist/editor/design.js.map +1 -0
- package/dist/editor/shell-page.js +111 -100
- package/dist/editor/shell-page.js.map +1 -1
- package/dist/publish/client.d.ts +60 -0
- package/dist/publish/client.js +16 -0
- package/dist/publish/client.js.map +1 -1
- package/dist/publish/fingerprint.d.ts +19 -13
- package/dist/publish/fingerprint.js +72 -68
- package/dist/publish/fingerprint.js.map +1 -1
- package/dist/publish/source-zip.d.ts +38 -0
- package/dist/publish/source-zip.js +131 -0
- package/dist/publish/source-zip.js.map +1 -0
- package/dist/scaffold/project-files.js +7 -1
- package/dist/scaffold/project-files.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Bitmagic design system, for the pages `bitmagic dev` serves.
|
|
3
|
+
*
|
|
4
|
+
* The dev view is a Bitmagic product surface — for a pro-lane creator it is the only one they ever
|
|
5
|
+
* look at — so it follows `creator/DESIGN.md` the way the Creator and the in-engine editor do.
|
|
6
|
+
* It cannot import the Creator's `BitmagicDesign.css`: this package ships on npm on its own, and
|
|
7
|
+
* both pages are strings assembled in TypeScript rather than bundled documents. So it re-declares
|
|
8
|
+
* the same tokens, exactly as `game/src/editor/editor-styles.ts` does for the engine's editor
|
|
9
|
+
* dialogs — three copies of the palette, one source of truth in DESIGN.md.
|
|
10
|
+
*
|
|
11
|
+
* **No backticks in anything exported here.** These constants are interpolated into the pages'
|
|
12
|
+
* template literals, and a backtick would end the literal somewhere else entirely (there is a test
|
|
13
|
+
* for it: `__tests__/shell-page.test.ts`).
|
|
14
|
+
*/
|
|
15
|
+
/** Hex tokens for TS-side use — the same set `game/src/editor/editor-styles.ts` exposes. */
|
|
16
|
+
export const BM = {
|
|
17
|
+
bg: '#0b0b0b',
|
|
18
|
+
surface: '#181818',
|
|
19
|
+
surfaceAlt: '#1f1f1f',
|
|
20
|
+
surfaceCard: '#252525',
|
|
21
|
+
textPrimary: '#ffffff',
|
|
22
|
+
textMuted: '#b3b3b3',
|
|
23
|
+
textDim: '#7c7c7c',
|
|
24
|
+
textOnAccent: '#000000',
|
|
25
|
+
border: '#4d4d4d',
|
|
26
|
+
borderMuted: '#2a2a2a',
|
|
27
|
+
aqua: '#A0DAB9',
|
|
28
|
+
aquaHover: '#B8E4CA',
|
|
29
|
+
aquaPressed: '#7DC29C',
|
|
30
|
+
pink: '#E0218A',
|
|
31
|
+
pinkHover: '#F04AA4',
|
|
32
|
+
pinkPressed: '#B3176D',
|
|
33
|
+
pumpkin: '#FF8200',
|
|
34
|
+
canary: '#F9E547',
|
|
35
|
+
shadowDialog: '0 8px 24px rgba(0, 0, 0, 0.5)',
|
|
36
|
+
shadowCard: '0 8px 8px rgba(0, 0, 0, 0.3)',
|
|
37
|
+
glowAqua: '0 0 24px rgba(160, 218, 185, 0.45)',
|
|
38
|
+
glowPink: '0 0 24px rgba(224, 33, 138, 0.4)',
|
|
39
|
+
insetBorderDim: 'inset 0 0 0 1px #7c7c7c',
|
|
40
|
+
insetBorderFocus: 'inset 0 0 0 1px #ffffff, 0 0 0 2px rgba(160, 218, 185, 0.45)',
|
|
41
|
+
font: '"Red Hat Display", "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif',
|
|
42
|
+
fontMono: 'ui-monospace, SFMono-Regular, Menlo, monospace',
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Red Hat Display, from the same Google Fonts URL `creator/index.html` uses.
|
|
46
|
+
*
|
|
47
|
+
* A dev machine with no network gets the fallback stack and a page that is otherwise identical —
|
|
48
|
+
* every rule below sizes and weights type rather than depending on the family's metrics.
|
|
49
|
+
*/
|
|
50
|
+
export const BITMAGIC_FONT_LINK = `<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
51
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
52
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Red+Hat+Display:wght@300;400;500;700&display=swap">`;
|
|
53
|
+
/** The palette as custom properties, so page-specific rules can `var(--bm-*)` them. */
|
|
54
|
+
export const BITMAGIC_TOKENS_CSS = `
|
|
55
|
+
:root {
|
|
56
|
+
color-scheme: dark;
|
|
57
|
+
--bm-bg: ${BM.bg};
|
|
58
|
+
--bm-surface: ${BM.surface};
|
|
59
|
+
--bm-surface-alt: ${BM.surfaceAlt};
|
|
60
|
+
--bm-surface-card: ${BM.surfaceCard};
|
|
61
|
+
--bm-text: ${BM.textPrimary};
|
|
62
|
+
--bm-text-muted: ${BM.textMuted};
|
|
63
|
+
--bm-text-dim: ${BM.textDim};
|
|
64
|
+
--bm-border: ${BM.border};
|
|
65
|
+
--bm-border-muted: ${BM.borderMuted};
|
|
66
|
+
--bm-aqua: ${BM.aqua};
|
|
67
|
+
--bm-aqua-hover: ${BM.aquaHover};
|
|
68
|
+
--bm-pink: ${BM.pink};
|
|
69
|
+
--bm-pink-hover: ${BM.pinkHover};
|
|
70
|
+
--bm-pumpkin: ${BM.pumpkin};
|
|
71
|
+
--bm-canary: ${BM.canary};
|
|
72
|
+
/* Accent washes. An accent at full strength behind body copy would be a coloured surface,
|
|
73
|
+
which DESIGN.md does not do — these are the same five accents at banner strength. */
|
|
74
|
+
--bm-tint-warning: rgba(255, 130, 0, .12);
|
|
75
|
+
--bm-tint-negative: rgba(224, 33, 138, .12);
|
|
76
|
+
--bm-tint-success: rgba(160, 218, 185, .18);
|
|
77
|
+
--bm-scrim: rgba(11, 11, 11, .78);
|
|
78
|
+
--bm-shadow-dialog: ${BM.shadowDialog};
|
|
79
|
+
--bm-shadow-card: ${BM.shadowCard};
|
|
80
|
+
--bm-glow-aqua: ${BM.glowAqua};
|
|
81
|
+
--bm-glow-pink: ${BM.glowPink};
|
|
82
|
+
--bm-font: ${BM.font};
|
|
83
|
+
--bm-font-mono: ${BM.fontMono};
|
|
84
|
+
}
|
|
85
|
+
`;
|
|
86
|
+
/**
|
|
87
|
+
* The component primitives both served pages use: pill buttons, inputs, badges, modal surfaces.
|
|
88
|
+
*
|
|
89
|
+
* Label voice is UPPERCASE Bold with tracking and content voice is sentence-case Regular, per the
|
|
90
|
+
* brand type guideline — which is why every button here is uppercase and nothing else is.
|
|
91
|
+
*/
|
|
92
|
+
export const BITMAGIC_CONTROLS_CSS = `
|
|
93
|
+
/* === Pill buttons =========================================================================
|
|
94
|
+
Secondary dark pill is the default: the toolbar is chrome, and DESIGN.md allows one primary
|
|
95
|
+
accent per screen. Aquamarine is spent on the active tab and on a dialog's confirm. */
|
|
96
|
+
.bm-pill {
|
|
97
|
+
background: var(--bm-surface-alt);
|
|
98
|
+
color: var(--bm-text);
|
|
99
|
+
border: 1px solid var(--bm-border);
|
|
100
|
+
border-radius: 9999px;
|
|
101
|
+
padding: 5px 14px;
|
|
102
|
+
font-family: var(--bm-font);
|
|
103
|
+
font-size: 12px;
|
|
104
|
+
font-weight: 700;
|
|
105
|
+
line-height: 1;
|
|
106
|
+
text-transform: uppercase;
|
|
107
|
+
letter-spacing: 1.4px;
|
|
108
|
+
cursor: pointer;
|
|
109
|
+
transition: background .15s ease, border-color .15s ease, color .15s ease,
|
|
110
|
+
box-shadow .15s ease, transform .15s ease;
|
|
111
|
+
}
|
|
112
|
+
.bm-pill:hover:not(:disabled) { background: var(--bm-surface-card); border-color: var(--bm-text-dim); }
|
|
113
|
+
.bm-pill:focus-visible { outline: none; box-shadow: 0 0 0 2px rgba(160, 218, 185, .45); }
|
|
114
|
+
.bm-pill:disabled { opacity: .5; cursor: default; }
|
|
115
|
+
|
|
116
|
+
/* Primary — the one creative action on a surface. Dark text: DESIGN.md forbids white on the
|
|
117
|
+
lighter accents. */
|
|
118
|
+
.bm-pill--primary {
|
|
119
|
+
background: var(--bm-aqua);
|
|
120
|
+
border-color: var(--bm-aqua);
|
|
121
|
+
color: #000000;
|
|
122
|
+
letter-spacing: 1.6px;
|
|
123
|
+
padding: 7px 20px;
|
|
124
|
+
}
|
|
125
|
+
.bm-pill--primary:hover:not(:disabled) {
|
|
126
|
+
background: var(--bm-aqua-hover);
|
|
127
|
+
border-color: var(--bm-aqua-hover);
|
|
128
|
+
transform: scale(1.03);
|
|
129
|
+
box-shadow: var(--bm-glow-aqua);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* Destructive — Shocking Pink, and only ever for discard / delete / reset. */
|
|
133
|
+
.bm-pill--destructive {
|
|
134
|
+
background: var(--bm-pink);
|
|
135
|
+
border-color: var(--bm-pink);
|
|
136
|
+
color: var(--bm-text);
|
|
137
|
+
letter-spacing: 1.6px;
|
|
138
|
+
}
|
|
139
|
+
.bm-pill--destructive:hover:not(:disabled) {
|
|
140
|
+
background: var(--bm-pink-hover);
|
|
141
|
+
border-color: var(--bm-pink-hover);
|
|
142
|
+
transform: scale(1.03);
|
|
143
|
+
box-shadow: var(--bm-glow-pink);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* Outlined — tertiary ("Cancel", "Close"). */
|
|
147
|
+
.bm-pill--ghost { background: transparent; border-color: var(--bm-text-dim); color: var(--bm-text-muted); }
|
|
148
|
+
.bm-pill--ghost:hover:not(:disabled) { background: transparent; border-color: var(--bm-text); color: var(--bm-text); }
|
|
149
|
+
|
|
150
|
+
/* === Input ================================================================================ */
|
|
151
|
+
.bm-input {
|
|
152
|
+
background: var(--bm-surface-alt);
|
|
153
|
+
color: var(--bm-text);
|
|
154
|
+
border: none;
|
|
155
|
+
box-shadow: ${BM.insetBorderDim};
|
|
156
|
+
border-radius: 6px;
|
|
157
|
+
padding: 10px 12px;
|
|
158
|
+
font-family: var(--bm-font);
|
|
159
|
+
font-size: 14px;
|
|
160
|
+
outline: none;
|
|
161
|
+
}
|
|
162
|
+
.bm-input:focus { box-shadow: ${BM.insetBorderFocus}; }
|
|
163
|
+
.bm-input::placeholder { color: var(--bm-text-muted); }
|
|
164
|
+
|
|
165
|
+
/* === Badge ================================================================================ */
|
|
166
|
+
.bm-badge {
|
|
167
|
+
display: inline-block;
|
|
168
|
+
border-radius: 9999px;
|
|
169
|
+
padding: 1px 7px;
|
|
170
|
+
font-size: 10.5px;
|
|
171
|
+
font-weight: 700;
|
|
172
|
+
line-height: 1.33;
|
|
173
|
+
text-transform: uppercase;
|
|
174
|
+
letter-spacing: 1.4px;
|
|
175
|
+
vertical-align: 1px;
|
|
176
|
+
background: var(--bm-surface-card);
|
|
177
|
+
color: var(--bm-text-muted);
|
|
178
|
+
}
|
|
179
|
+
/* Success / featured, and warning. Never both on one row — an asset is one or the other. */
|
|
180
|
+
.bm-badge--success { background: var(--bm-aqua); color: #000000; }
|
|
181
|
+
.bm-badge--warning { background: var(--bm-pumpkin); color: #000000; }
|
|
182
|
+
|
|
183
|
+
/* === Label voice ==========================================================================
|
|
184
|
+
Section headers and anything else speaking as a label rather than as content. */
|
|
185
|
+
.bm-label {
|
|
186
|
+
font-size: 12px;
|
|
187
|
+
font-weight: 700;
|
|
188
|
+
text-transform: uppercase;
|
|
189
|
+
letter-spacing: 1.4px;
|
|
190
|
+
color: var(--bm-text-muted);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/* === Modal ================================================================================ */
|
|
194
|
+
.bm-overlay {
|
|
195
|
+
display: none;
|
|
196
|
+
position: fixed;
|
|
197
|
+
inset: 0;
|
|
198
|
+
background: var(--bm-scrim);
|
|
199
|
+
align-items: center;
|
|
200
|
+
justify-content: center;
|
|
201
|
+
}
|
|
202
|
+
.bm-overlay.show { display: flex; }
|
|
203
|
+
.bm-dialog {
|
|
204
|
+
background: var(--bm-surface);
|
|
205
|
+
border: 1px solid var(--bm-border-muted);
|
|
206
|
+
border-radius: 8px;
|
|
207
|
+
box-shadow: var(--bm-shadow-dialog);
|
|
208
|
+
}
|
|
209
|
+
.bm-dialog h2 {
|
|
210
|
+
margin: 0 0 6px;
|
|
211
|
+
font-size: 16px;
|
|
212
|
+
font-weight: 700;
|
|
213
|
+
text-transform: uppercase;
|
|
214
|
+
letter-spacing: .5px;
|
|
215
|
+
}
|
|
216
|
+
`;
|
|
217
|
+
//# sourceMappingURL=design.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design.js","sourceRoot":"","sources":["../../src/editor/design.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,4FAA4F;AAC5F,MAAM,CAAC,MAAM,EAAE,GAAG;IAChB,EAAE,EAAE,SAAS;IACb,OAAO,EAAE,SAAS;IAClB,UAAU,EAAE,SAAS;IACrB,WAAW,EAAE,SAAS;IAEtB,WAAW,EAAE,SAAS;IACtB,SAAS,EAAE,SAAS;IACpB,OAAO,EAAE,SAAS;IAClB,YAAY,EAAE,SAAS;IAEvB,MAAM,EAAE,SAAS;IACjB,WAAW,EAAE,SAAS;IAEtB,IAAI,EAAE,SAAS;IACf,SAAS,EAAE,SAAS;IACpB,WAAW,EAAE,SAAS;IACtB,IAAI,EAAE,SAAS;IACf,SAAS,EAAE,SAAS;IACpB,WAAW,EAAE,SAAS;IACtB,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,SAAS;IAEjB,YAAY,EAAE,+BAA+B;IAC7C,UAAU,EAAE,8BAA8B;IAC1C,QAAQ,EAAE,oCAAoC;IAC9C,QAAQ,EAAE,kCAAkC;IAC5C,cAAc,EAAE,yBAAyB;IACzC,gBAAgB,EAAE,8DAA8D;IAEhF,IAAI,EAAE,8EAA8E;IACpF,QAAQ,EAAE,gDAAgD;CAClD,CAAC;AAEX;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;;0HAEwF,CAAC;AAE3H,uFAAuF;AACvF,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;eAGpB,EAAE,CAAC,EAAE;oBACA,EAAE,CAAC,OAAO;wBACN,EAAE,CAAC,UAAU;yBACZ,EAAE,CAAC,WAAW;iBACtB,EAAE,CAAC,WAAW;uBACR,EAAE,CAAC,SAAS;qBACd,EAAE,CAAC,OAAO;mBACZ,EAAE,CAAC,MAAM;yBACH,EAAE,CAAC,WAAW;iBACtB,EAAE,CAAC,IAAI;uBACD,EAAE,CAAC,SAAS;iBAClB,EAAE,CAAC,IAAI;uBACD,EAAE,CAAC,SAAS;oBACf,EAAE,CAAC,OAAO;mBACX,EAAE,CAAC,MAAM;;;;;;;0BAOF,EAAE,CAAC,YAAY;wBACjB,EAAE,CAAC,UAAU;sBACf,EAAE,CAAC,QAAQ;sBACX,EAAE,CAAC,QAAQ;iBAChB,EAAE,CAAC,IAAI;sBACF,EAAE,CAAC,QAAQ;;CAEhC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA+DnB,EAAE,CAAC,cAAc;;;;;;;kCAOD,EAAE,CAAC,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsDpD,CAAC"}
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
import { decodeForgeMapHeights, renderForgeMapRgba, } from '@bitmagic/world-forger/pipeline/forge-map-render.js';
|
|
52
52
|
import { FORGE_MAP_PALETTE } from '@bitmagic/world-forger/pipeline/layout-map.js';
|
|
53
53
|
import { ASSET_DETAIL_CSS, ASSET_DETAIL_HTML } from './asset-detail-panel.js';
|
|
54
|
+
import { BITMAGIC_CONTROLS_CSS, BITMAGIC_FONT_LINK, BITMAGIC_TOKENS_CSS } from './design.js';
|
|
54
55
|
/** How often the shell asks the engine whether anything changed. A `Set` read; effectively free. */
|
|
55
56
|
const POLL_INTERVAL_MS = 500;
|
|
56
57
|
/**
|
|
@@ -104,134 +105,143 @@ export function renderEditorShell(options) {
|
|
|
104
105
|
<head>
|
|
105
106
|
<meta charset="utf-8">
|
|
106
107
|
<title>bitmagic dev — ${escapeAttr(options.gameId)}</title>
|
|
108
|
+
${BITMAGIC_FONT_LINK}
|
|
107
109
|
<style>
|
|
108
|
-
|
|
110
|
+
${BITMAGIC_TOKENS_CSS}
|
|
111
|
+
${BITMAGIC_CONTROLS_CSS}
|
|
109
112
|
* { box-sizing: border-box; }
|
|
110
113
|
/* Flex column rather than calc() heights: the banners come and go, and three of them at once
|
|
111
114
|
must not push the viewport into a scrollbar. */
|
|
112
115
|
body { margin: 0; height: 100vh; display: flex; flex-direction: column;
|
|
113
|
-
background:
|
|
114
|
-
#bar { display: flex; align-items: center; gap: 12px; height:
|
|
115
|
-
background:
|
|
116
|
-
|
|
116
|
+
background: var(--bm-bg); color: var(--bm-text); font: 400 14px/1.5 var(--bm-font); }
|
|
117
|
+
#bar { display: flex; align-items: center; gap: 12px; height: 44px; flex: none; padding: 0 16px;
|
|
118
|
+
background: var(--bm-surface); border-bottom: 1px solid var(--bm-border-muted); }
|
|
119
|
+
/* The wordmark speaks in the brand's headline voice: uppercase, bold, tracked. */
|
|
120
|
+
#bar .wordmark { font-size: 14px; font-weight: 700; text-transform: uppercase;
|
|
121
|
+
letter-spacing: 1.6px; }
|
|
122
|
+
#bar .id { color: var(--bm-text-dim); font-family: var(--bm-font-mono); font-size: 12px; }
|
|
117
123
|
#bar .spacer { flex: 1; }
|
|
118
|
-
#tabs { display: flex; gap:
|
|
119
|
-
padding:
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
.tab
|
|
123
|
-
.tab.active { background:
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
#
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
124
|
+
#tabs { display: flex; gap: 4px; background: var(--bm-surface-alt); border-radius: 9999px;
|
|
125
|
+
padding: 3px; }
|
|
126
|
+
/* A tab is a .bm-pill that starts invisible; the ACTIVE one is what the accent is for —
|
|
127
|
+
DESIGN.md gives Aquamarine to primary actions and active states alike. */
|
|
128
|
+
.tab { background: transparent; border-color: transparent; color: var(--bm-text-muted); }
|
|
129
|
+
.tab:hover:not(.active) { background: var(--bm-surface-card); border-color: transparent;
|
|
130
|
+
color: var(--bm-text); }
|
|
131
|
+
.tab.active, .tab.active:hover { background: var(--bm-aqua); border-color: var(--bm-aqua);
|
|
132
|
+
color: #000000; }
|
|
133
|
+
#status { display: flex; align-items: center; gap: 8px; font-size: 12px;
|
|
134
|
+
color: var(--bm-text-muted); }
|
|
135
|
+
/* Working is Pumpkin, done is Aquamarine, failed is Shocking Pink — the same three the steps,
|
|
136
|
+
the progress bar and the banners below use, so one colour never means two things. */
|
|
137
|
+
#dot { width: 8px; height: 8px; border-radius: 50%; background: var(--bm-border); }
|
|
138
|
+
#dot.saving { background: var(--bm-pumpkin); }
|
|
139
|
+
#dot.saved { background: var(--bm-aqua); }
|
|
140
|
+
#dot.error { background: var(--bm-pink); }
|
|
141
|
+
#auto { display: flex; align-items: center; gap: 6px; font-size: 12px;
|
|
142
|
+
color: var(--bm-text-muted); cursor: pointer; }
|
|
143
|
+
#auto input { margin: 0; accent-color: var(--bm-aqua); }
|
|
144
|
+
.banner { display: none; align-items: center; gap: 12px; flex: none; padding: 10px 16px;
|
|
145
|
+
background: var(--bm-tint-warning); border-bottom: 1px solid var(--bm-pumpkin);
|
|
146
|
+
color: var(--bm-text); }
|
|
139
147
|
.banner.show { display: flex; }
|
|
140
|
-
|
|
141
|
-
#build-banner
|
|
148
|
+
/* A lost edit and a broken build are worse than out-of-date, and read as negative states. */
|
|
149
|
+
#terrain-banner, #build-banner { background: var(--bm-tint-negative);
|
|
150
|
+
border-bottom-color: var(--bm-pink); }
|
|
151
|
+
#build-banner code, #terrain-banner code { font-family: var(--bm-font-mono); }
|
|
142
152
|
/* The game and the panel share one row, so the panel takes width from the game rather than
|
|
143
153
|
overlaying it — an overlay would cover the thing you opened the panel to watch. */
|
|
144
154
|
#stage { flex: 1; display: flex; min-height: 0; }
|
|
145
155
|
#frame { display: block; flex: 1; border: 0; min-width: 0; height: 100%; }
|
|
146
|
-
#assets { width:
|
|
147
|
-
border-left: 1px solid
|
|
156
|
+
#assets { width: 280px; flex: none; overflow-y: auto; background: var(--bm-surface);
|
|
157
|
+
border-left: 1px solid var(--bm-border-muted); }
|
|
148
158
|
body.assets-closed #assets { display: none; }
|
|
149
|
-
#assets-head { position: sticky; top: 0; display: flex; align-items: center; gap: 8px;
|
|
150
|
-
padding:
|
|
151
|
-
|
|
152
|
-
#assets-head .count { margin-left: auto; color:
|
|
153
|
-
#assets-empty { padding:
|
|
154
|
-
.row { display: flex; gap:
|
|
159
|
+
#assets-head { position: sticky; top: 0; display: flex; align-items: center; gap: 8px; z-index: 1;
|
|
160
|
+
padding: 12px; background: var(--bm-surface-alt);
|
|
161
|
+
border-bottom: 1px solid var(--bm-border-muted); }
|
|
162
|
+
#assets-head .count { margin-left: auto; color: var(--bm-text-dim); letter-spacing: 0; }
|
|
163
|
+
#assets-empty { padding: 16px 12px; color: var(--bm-text-dim); font-size: 12px; }
|
|
164
|
+
.row { display: flex; gap: 12px; padding: 10px 12px;
|
|
165
|
+
border-bottom: 1px solid var(--bm-border-muted); }
|
|
155
166
|
.row.clickable { cursor: pointer; }
|
|
156
|
-
.row.clickable:hover, .row.clickable:focus-visible { background:
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
167
|
+
.row.clickable:hover, .row.clickable:focus-visible { background: var(--bm-surface-card);
|
|
168
|
+
outline: none; }
|
|
169
|
+
.row .thumb { width: 48px; height: 48px; flex: none; border-radius: 6px;
|
|
170
|
+
background: var(--bm-surface-alt); display: flex; align-items: center;
|
|
171
|
+
justify-content: center; font-size: 18px; color: var(--bm-text-dim);
|
|
172
|
+
overflow: hidden; }
|
|
160
173
|
.row .thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
|
161
174
|
.row .body { min-width: 0; flex: 1; }
|
|
162
|
-
.row .name { color:
|
|
163
|
-
.row .meta { color: #6a6a7a; font-size: 11px; overflow: hidden; text-overflow: ellipsis;
|
|
175
|
+
.row .name { color: var(--bm-text); overflow: hidden; text-overflow: ellipsis;
|
|
164
176
|
white-space: nowrap; }
|
|
165
|
-
.row .
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
177
|
+
.row .name .bm-badge { margin-left: 6px; }
|
|
178
|
+
.row .meta { color: var(--bm-text-dim); font-size: 12px; overflow: hidden;
|
|
179
|
+
text-overflow: ellipsis; white-space: nowrap; }
|
|
180
|
+
/* A new asset during a forge is the whole show, so it announces itself with the Aquamarine
|
|
181
|
+
"something landed" flourish and then settles. */
|
|
170
182
|
.row.fresh { animation: landed 2.4s ease-out; }
|
|
171
|
-
@keyframes landed { from { background:
|
|
172
|
-
.row.job .thumb { color:
|
|
173
|
-
.row.job .message { color:
|
|
174
|
-
white-space: nowrap; }
|
|
183
|
+
@keyframes landed { from { background: var(--bm-tint-success); } to { background: transparent; } }
|
|
184
|
+
.row.job .thumb { color: var(--bm-pumpkin); }
|
|
185
|
+
.row.job .message { color: var(--bm-text-muted); font-size: 12px; overflow: hidden;
|
|
186
|
+
text-overflow: ellipsis; white-space: nowrap; }
|
|
175
187
|
/* The forge's five steps. A whole run is half an hour, so this is what the panel is for. */
|
|
176
|
-
.steps { margin-top:
|
|
177
|
-
.step { display: flex; align-items: baseline; gap:
|
|
178
|
-
|
|
179
|
-
.step.
|
|
180
|
-
.step
|
|
188
|
+
.steps { margin-top: 6px; font-size: 12px; }
|
|
189
|
+
.step { display: flex; align-items: baseline; gap: 6px; color: var(--bm-text-dim);
|
|
190
|
+
line-height: 1.6; }
|
|
191
|
+
.step.running { color: var(--bm-text); }
|
|
192
|
+
.step.done { color: var(--bm-aqua); }
|
|
193
|
+
.step .glyph { width: 10px; flex: none; text-align: center; }
|
|
181
194
|
.step .label { flex: none; }
|
|
182
195
|
.step .tail { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis;
|
|
183
|
-
white-space: nowrap; color:
|
|
184
|
-
.step.running .tail { color:
|
|
185
|
-
.bar { height: 3px; margin:
|
|
186
|
-
overflow: hidden; }
|
|
187
|
-
.bar .fill { height: 100%; background:
|
|
196
|
+
white-space: nowrap; color: var(--bm-text-dim); }
|
|
197
|
+
.step.running .tail { color: var(--bm-text-muted); }
|
|
198
|
+
.bar { height: 3px; margin: 4px 0 4px 16px; border-radius: 2px;
|
|
199
|
+
background: var(--bm-surface-card); overflow: hidden; }
|
|
200
|
+
.bar .fill { height: 100%; background: var(--bm-pumpkin); }
|
|
188
201
|
/* The level's shape, drawn from the forge artifact — twenty-plus minutes before it is playable.
|
|
189
202
|
image-rendering: pixelated because the canvas is drawn at an integer multiple of the raster
|
|
190
203
|
and any further scaling should keep the object dots as dots. */
|
|
191
|
-
.job-map { margin-top:
|
|
192
|
-
.job-map canvas { display: block; width: 100%; height: auto; border-radius:
|
|
193
|
-
border: 1px solid
|
|
204
|
+
.job-map { margin-top: 8px; }
|
|
205
|
+
.job-map canvas { display: block; width: 100%; height: auto; border-radius: 6px;
|
|
206
|
+
border: 1px solid var(--bm-border-muted); image-rendering: pixelated; }
|
|
194
207
|
/* What the level being built contains — known minutes before the level itself exists. */
|
|
195
|
-
.job-summary { margin-top:
|
|
196
|
-
|
|
197
|
-
|
|
208
|
+
.job-summary { margin-top: 8px; padding-top: 8px;
|
|
209
|
+
border-top: 1px solid var(--bm-border-muted); color: var(--bm-text-muted);
|
|
210
|
+
font-size: 12px; line-height: 1.6; }
|
|
211
|
+
.job-summary .objects { color: var(--bm-text-dim); overflow: hidden; text-overflow: ellipsis;
|
|
198
212
|
white-space: nowrap; }
|
|
199
213
|
.spin { display: inline-block; animation: spin 1.4s linear infinite; }
|
|
200
214
|
@keyframes spin { to { transform: rotate(360deg); } }
|
|
201
|
-
#hq-overlay {
|
|
202
|
-
|
|
203
|
-
#hq-
|
|
204
|
-
#hq-
|
|
205
|
-
|
|
206
|
-
#hq-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
background: #101014; color: #e6e6ea; border: 1px solid #34343f; font: inherit; }
|
|
210
|
-
#hq-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 12px; }
|
|
211
|
-
#hq-confirm { background: #3352c4; border-color: #3f61d8; }
|
|
212
|
-
#hq-note { display: none; margin-top: 10px; padding: 10px; border-radius: 6px;
|
|
213
|
-
background: #101014; border: 1px solid #26262e; }
|
|
215
|
+
#hq-overlay { z-index: 10; }
|
|
216
|
+
#hq-dialog { width: min(560px, 92vw); padding: 20px; }
|
|
217
|
+
#hq-dialog p { margin: 0 0 16px; color: var(--bm-text-muted); }
|
|
218
|
+
#hq-prompt { width: 100%; min-height: 88px; resize: vertical; }
|
|
219
|
+
#hq-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }
|
|
220
|
+
#hq-note { display: none; margin-top: 12px; padding: 12px; border-radius: 6px; font-size: 12px;
|
|
221
|
+
background: var(--bm-surface-alt); border: 1px solid var(--bm-border-muted);
|
|
222
|
+
color: var(--bm-text-muted); }
|
|
214
223
|
#hq-note.show { display: block; }
|
|
215
|
-
#hq-note code { display: block; margin-top: 6px; color:
|
|
224
|
+
#hq-note code { display: block; margin-top: 6px; color: var(--bm-aqua);
|
|
225
|
+
font-family: var(--bm-font-mono); word-break: break-all; }
|
|
216
226
|
${ASSET_DETAIL_CSS}
|
|
217
227
|
</style>
|
|
218
228
|
</head>
|
|
219
229
|
<body>
|
|
220
230
|
<div id="bar">
|
|
221
|
-
<
|
|
231
|
+
<span class="wordmark">bitmagic dev</span>
|
|
222
232
|
<span class="id">${escapeAttr(options.gameId)}</span>
|
|
223
233
|
<div id="tabs">
|
|
224
|
-
<button class="tab active" type="button" data-tab="game">Game</button>
|
|
225
|
-
<button class="tab" type="button" data-tab="editor">Editor</button>
|
|
234
|
+
<button class="tab bm-pill active" type="button" data-tab="game">Game</button>
|
|
235
|
+
<button class="tab bm-pill" type="button" data-tab="editor">Editor</button>
|
|
226
236
|
</div>
|
|
227
237
|
<span class="spacer"></span>
|
|
228
238
|
<label id="auto" title="Reload the game when the project changes on disk">
|
|
229
239
|
<input id="auto-toggle" type="checkbox" checked> Auto-reload
|
|
230
240
|
</label>
|
|
231
241
|
<span id="status"><span id="dot"></span><span id="status-text">Loading…</span></span>
|
|
232
|
-
<button id="assets-toggle" type="button" title="Show the assets in this project and what is being
|
|
233
|
-
<button id="shot" type="button" title="Copy the current frame to the clipboard">Screenshot</button>
|
|
234
|
-
<button id="reload" type="button">Reload</button>
|
|
242
|
+
<button id="assets-toggle" class="bm-pill" type="button" title="Show the assets in this project and what is being made">Assets</button>
|
|
243
|
+
<button id="shot" class="bm-pill" type="button" title="Copy the current frame to the clipboard">Screenshot</button>
|
|
244
|
+
<button id="reload" class="bm-pill" type="button">Reload</button>
|
|
235
245
|
</div>
|
|
236
246
|
<div id="build-banner" class="banner">
|
|
237
247
|
<span id="build-message"></span>
|
|
@@ -239,32 +249,32 @@ ${ASSET_DETAIL_CSS}
|
|
|
239
249
|
</div>
|
|
240
250
|
<div id="banner" class="banner">
|
|
241
251
|
<span>src/work/world.json changed on disk — this scene is out of date.</span>
|
|
242
|
-
<button id="banner-reload" type="button">Reload scene</button>
|
|
252
|
+
<button id="banner-reload" class="bm-pill" type="button">Reload scene</button>
|
|
243
253
|
</div>
|
|
244
254
|
<div id="terrain-banner" class="banner">
|
|
245
255
|
<span><strong>Terrain edits are not saved yet.</strong>
|
|
246
256
|
Sculpting the ground needs an asset upload that <code>bitmagic dev</code> does not do — these
|
|
247
257
|
voxel changes will be lost. Discard them, or press Cancel in the terrain toolbar.</span>
|
|
248
|
-
<button id="terrain-discard" type="button">Discard terrain edits</button>
|
|
258
|
+
<button id="terrain-discard" class="bm-pill bm-pill--destructive" type="button">Discard terrain edits</button>
|
|
249
259
|
</div>
|
|
250
260
|
<div id="stage">
|
|
251
261
|
<iframe id="frame" allow="autoplay; fullscreen; xr-spatial-tracking; clipboard-write"></iframe>
|
|
252
262
|
<aside id="assets">
|
|
253
|
-
<div id="assets-head">Assets<span class="count" id="assets-count"></span></div>
|
|
263
|
+
<div id="assets-head" class="bm-label">Assets<span class="count" id="assets-count"></span></div>
|
|
254
264
|
<div id="assets-jobs"></div>
|
|
255
265
|
<div id="assets-list"></div>
|
|
256
|
-
<div id="assets-empty">Nothing yet. Assets appear here as they are
|
|
266
|
+
<div id="assets-empty">Nothing yet. Assets appear here as they are made.</div>
|
|
257
267
|
</aside>
|
|
258
268
|
</div>
|
|
259
|
-
<div id="hq-overlay">
|
|
260
|
-
<div id="hq-dialog">
|
|
261
|
-
<h2>
|
|
269
|
+
<div id="hq-overlay" class="bm-overlay">
|
|
270
|
+
<div id="hq-dialog" class="bm-dialog">
|
|
271
|
+
<h2>Make a high-quality <span id="hq-name"></span></h2>
|
|
262
272
|
<p>Describe what this object should be. The text is saved as the asset's description and
|
|
263
|
-
used as the
|
|
264
|
-
<textarea id="hq-prompt" placeholder="e.g. a weathered stone archway covered in moss"></textarea>
|
|
273
|
+
used as the prompt it is made from.</p>
|
|
274
|
+
<textarea id="hq-prompt" class="bm-input" placeholder="e.g. a weathered stone archway covered in moss"></textarea>
|
|
265
275
|
<div id="hq-actions">
|
|
266
|
-
<button id="hq-cancel" type="button">Close</button>
|
|
267
|
-
<button id="hq-confirm" type="button">
|
|
276
|
+
<button id="hq-cancel" class="bm-pill bm-pill--ghost" type="button">Close</button>
|
|
277
|
+
<button id="hq-confirm" class="bm-pill bm-pill--primary" type="button">Make it</button>
|
|
268
278
|
</div>
|
|
269
279
|
<div id="hq-note">
|
|
270
280
|
<span id="hq-note-text"></span>
|
|
@@ -1101,8 +1111,9 @@ ${ASSET_DETAIL_HTML}
|
|
|
1101
1111
|
|
|
1102
1112
|
var body = el('div', 'body');
|
|
1103
1113
|
var name = el('div', 'name', asset.name || asset.id || 'unnamed');
|
|
1104
|
-
|
|
1105
|
-
|
|
1114
|
+
// Success and warning, never both: an asset is either the good version or standing in for it.
|
|
1115
|
+
if (asset.hqGeneratedAt) name.appendChild(el('span', 'bm-badge bm-badge--success', 'HQ'));
|
|
1116
|
+
else if (asset.placeholder === true) name.appendChild(el('span', 'bm-badge bm-badge--warning', 'placeholder'));
|
|
1106
1117
|
body.appendChild(name);
|
|
1107
1118
|
var bits = [asset.type || 'unknown'];
|
|
1108
1119
|
var size = formatSize(asset.size);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-page.js","sourceRoot":"","sources":["../../src/editor/shell-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,EACL,qBAAqB,EAAE,kBAAkB,GAC1C,MAAM,qDAAqD,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AAClF,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"shell-page.js","sourceRoot":"","sources":["../../src/editor/shell-page.ts"],"names":[],"mappings":"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"}
|
package/dist/publish/client.d.ts
CHANGED
|
@@ -24,6 +24,21 @@ export interface BeginPublishRequest {
|
|
|
24
24
|
* server simply ignores a field it does not read — the game then keeps its default icon.
|
|
25
25
|
*/
|
|
26
26
|
faviconSourceUrl?: string;
|
|
27
|
+
/**
|
|
28
|
+
* sha256 of the source archive this publish is about to upload.
|
|
29
|
+
*
|
|
30
|
+
* Sent on BEGIN, unlike everything else about the archive, because `begin` bakes it into the
|
|
31
|
+
* meta block it mints — which is the whole mechanism: `complete` already verifies that block
|
|
32
|
+
* byte-for-byte against what actually landed, so binding the archive's hash into it makes the
|
|
33
|
+
* published bundle carry a claim about which source produced it, at no extra read. That is only
|
|
34
|
+
* possible if the archive is built and hashed BEFORE this call, which is why `runPublish`
|
|
35
|
+
* zips before it begins.
|
|
36
|
+
*
|
|
37
|
+
* Optional: a failure to build the archive must not fail the publish, and an older server
|
|
38
|
+
* ignores a field it does not read (it then mints a block without the line, and `complete`
|
|
39
|
+
* re-renders without it too — see `renderMetaBlock`).
|
|
40
|
+
*/
|
|
41
|
+
sourceSha256?: string;
|
|
27
42
|
}
|
|
28
43
|
export interface BeginPublishResponse {
|
|
29
44
|
signedUrl: string;
|
|
@@ -44,6 +59,18 @@ export interface BeginPublishResponse {
|
|
|
44
59
|
* CLI says nothing rather than guessing.
|
|
45
60
|
*/
|
|
46
61
|
currentEngineVersion: string | null;
|
|
62
|
+
/**
|
|
63
|
+
* Where to PUT the source archive, and the key it lands at.
|
|
64
|
+
*
|
|
65
|
+
* The server mints the key (it carries a random segment, so the archive cannot be enumerated
|
|
66
|
+
* from a game's public id) — the CLI never proposes one. Both absent when no `sourceSha256`
|
|
67
|
+
* was sent, or when talking to a server that predates this; the CLI then simply publishes
|
|
68
|
+
* without an archive, exactly as it did before.
|
|
69
|
+
*/
|
|
70
|
+
sourceSignedUrl?: string;
|
|
71
|
+
sourceKey?: string;
|
|
72
|
+
/** Must be echoed on the archive PUT — bound into the signature, same contract as the bundle. */
|
|
73
|
+
sourceCacheControl?: string;
|
|
47
74
|
}
|
|
48
75
|
export declare function beginPublish(environment: Environment, accessToken: string, body: BeginPublishRequest, deps: ApiDeps): Promise<BeginPublishResponse>;
|
|
49
76
|
export interface CompletePublishRequest {
|
|
@@ -74,11 +101,36 @@ export interface CompletePublishRequest {
|
|
|
74
101
|
*/
|
|
75
102
|
engineVersion: string;
|
|
76
103
|
fingerprint: string;
|
|
104
|
+
/**
|
|
105
|
+
* The source archive that was uploaded, so `complete` can audit it: the key `begin` minted
|
|
106
|
+
* (echoed, not proposed — the server re-derives the expected shape and refuses anything else)
|
|
107
|
+
* and the hash that was bound into the meta block.
|
|
108
|
+
*
|
|
109
|
+
* All three optional together. They are absent when the archive could not be built, and absent
|
|
110
|
+
* from every already-installed CLI — so `complete` must treat missing as "cannot check", not as
|
|
111
|
+
* a failure. Making them required would break every publish in the field the moment the server
|
|
112
|
+
* deploys.
|
|
113
|
+
*/
|
|
114
|
+
sourceKey?: string;
|
|
115
|
+
sourceSha256?: string;
|
|
116
|
+
/**
|
|
117
|
+
* Which fingerprint algorithm produced `fingerprint`. The server keeps every version it has
|
|
118
|
+
* shipped and dispatches on this, because a creator's pinned CLI and the running server are
|
|
119
|
+
* routinely different copies of the shared code — see SOURCE_INDEX_ALGO.
|
|
120
|
+
*/
|
|
121
|
+
fingerprintAlgo?: string;
|
|
122
|
+
}
|
|
123
|
+
/** Per-check outcome from the server's source audit. Advisory: none of it changes the exit code. */
|
|
124
|
+
export interface SourceCheckResult {
|
|
125
|
+
status: 'pass' | 'warn' | 'skip';
|
|
126
|
+
warnings?: string[];
|
|
77
127
|
}
|
|
78
128
|
export interface CompletePublishResponse {
|
|
79
129
|
url: string;
|
|
80
130
|
publishVersion: number;
|
|
81
131
|
visibility: 'public' | 'private';
|
|
132
|
+
/** Absent from an older server; the CLI then prints nothing. */
|
|
133
|
+
sourceChecks?: SourceCheckResult;
|
|
82
134
|
}
|
|
83
135
|
export declare function completePublish(environment: Environment, accessToken: string, body: CompletePublishRequest, deps: ApiDeps): Promise<CompletePublishResponse>;
|
|
84
136
|
/**
|
|
@@ -89,6 +141,14 @@ export declare function completePublish(environment: Environment, accessToken: s
|
|
|
89
141
|
export declare const PUBLISH_BUNDLE_CONTENT_TYPE = "text/html";
|
|
90
142
|
/** PUT the built (and meta-block-injected) bundle to the signed URL `begin` minted. */
|
|
91
143
|
export declare function putBundle(signedUrl: string, html: string, cacheControl: string, deps: ApiDeps): Promise<void>;
|
|
144
|
+
/**
|
|
145
|
+
* `begin` signs the source archive as `application/zip`. Fixed here for the same reason as
|
|
146
|
+
* PUBLISH_BUNDLE_CONTENT_TYPE: the response echoes no content type because there is nothing to
|
|
147
|
+
* echo — this is the one value the signature can have been minted with.
|
|
148
|
+
*/
|
|
149
|
+
export declare const PUBLISH_SOURCE_CONTENT_TYPE = "application/zip";
|
|
150
|
+
/** PUT the source archive to the signed URL `begin` minted. */
|
|
151
|
+
export declare function putSourceArchive(signedUrl: string, body: Uint8Array, cacheControl: string, deps: ApiDeps): Promise<void>;
|
|
92
152
|
export interface ThumbnailUploadRequest {
|
|
93
153
|
gameId: string;
|
|
94
154
|
filename: string;
|