@dcl-regenesislabs/web-editor 0.3.16-40498300506.commit-c2a0d59 → 0.3.16-40596302895.commit-0ee155d
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/editor.js +608 -428
- package/package.json +2 -2
- package/prefabs/admin-tools/data.json +5 -1
- package/prefabs/admin-tools/scripts/admin.tsx +3 -2
- package/prefabs/announcer/data.json +5 -1
- package/prefabs/announcer/scripts/announcer.tsx +5 -6
- package/prefabs/catalog.json +1 -1
- package/prefabs/game-flow/data.json +7 -3
- package/prefabs/game-flow/scripts/game-flow.ts +1 -1
- package/prefabs/leaderboard/ai.md +2 -2
- package/prefabs/leaderboard/data.json +5 -1
- package/prefabs/leaderboard/scripts/leaderboard-hud.tsx +22 -21
- package/prefabs/leaderboard/scripts/leaderboard.ts +1 -1
- package/prefabs/run-progress/ai.md +3 -2
- package/prefabs/run-progress/data.json +5 -1
- package/prefabs/run-progress/scripts/run-progress.tsx +14 -16
- package/prefabs/server-clock/ai.md +2 -2
- package/prefabs/server-clock/data.json +5 -1
- package/prefabs/server-clock/scripts/server-clock.ts +1 -1
- package/prefabs/ui-theme/ai.md +4 -2
- package/prefabs/ui-theme/data.json +5 -1
|
@@ -13,8 +13,12 @@
|
|
|
13
13
|
"board"
|
|
14
14
|
],
|
|
15
15
|
"requiresSdk": "auth-server",
|
|
16
|
-
"version": "1.
|
|
16
|
+
"version": "1.6.0",
|
|
17
17
|
"changelog": [
|
|
18
|
+
{
|
|
19
|
+
"version": "1.6.0",
|
|
20
|
+
"notes": "The on-screen board takes its place in the shared HUD layout, so it no longer overlaps other HUDs, and shows the top 5 on phones, whose screen is a third shorter."
|
|
21
|
+
},
|
|
18
22
|
{
|
|
19
23
|
"version": "1.5.0",
|
|
20
24
|
"notes": "Before the first score the board tells players \"No scores yet — be the first!\" (or \"No times yet\" for times) instead of setup instructions, and its text wraps to stay inside the panel. A board placed before this keeps its old text size, where the new line already fits."
|
|
@@ -1,28 +1,29 @@
|
|
|
1
|
-
import ReactEcs, {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
1
|
+
import ReactEcs, { UiEntity } from '@dcl/sdk/react-ecs'
|
|
2
|
+
import { isMobile } from '@dcl/sdk/platform'
|
|
3
|
+
import { sceneUiTheme } from '~runtime/uiTheme'
|
|
4
4
|
import { UiPanel, UiText } from '~runtime/uiComponents'
|
|
5
|
+
import { addHudItem, HUD_COLUMN_WIDTH } from '~runtime/hudLayout'
|
|
5
6
|
import { formatScore, rowLabel, type BoardRow, type BoardSort } from './pure/board'
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
const ROW = 36
|
|
9
|
+
|
|
10
|
+
export function mountLeaderboardHud(position: 'left' | 'right', read: () => {
|
|
8
11
|
title: string; rows: BoardRow[]; sort: BoardSort; empty: string
|
|
9
|
-
}): void {
|
|
10
|
-
|
|
12
|
+
}): () => void {
|
|
13
|
+
return addHudItem(position === 'left' ? 'left' : 'right', () => {
|
|
11
14
|
const theme = sceneUiTheme()
|
|
12
15
|
const board = read()
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
{
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
</UiEntity>
|
|
27
|
-
}, UI_CANVAS)
|
|
16
|
+
// a phone's screen is a third shorter
|
|
17
|
+
const rows = board.rows.slice(0, isMobile() ? 5 : 10)
|
|
18
|
+
return <UiPanel theme={theme} uiTransform={{ width: HUD_COLUMN_WIDTH, height: 100 + Math.max(1, rows.length) * ROW, padding: 20 }}>
|
|
19
|
+
<UiText value={board.title} color={theme.text} size={24} height={36} />
|
|
20
|
+
<UiText value={board.sort === 'asc' ? 'FASTEST TIMES' : 'HIGH SCORES'} color={theme.muted} size={16} height={24} />
|
|
21
|
+
{rows.length === 0 && <UiText value={board.empty} color={theme.muted} size={16} height={ROW} />}
|
|
22
|
+
{rows.map((row) => <UiEntity key={row.player} uiTransform={{ width: '100%', height: ROW, pointerFilter: 'none' }}>
|
|
23
|
+
<UiText value={String(row.rank).padStart(2, '0')} color={theme.accentText} size={16} mono uiTransform={{ width: 36 }} height={ROW} />
|
|
24
|
+
<UiText value={rowLabel(row)} color={theme.text} size={18} uiTransform={{ width: 176 }} height={ROW} />
|
|
25
|
+
<UiText value={formatScore(row.score, board.sort)} color={theme.text} size={18} mono align="middle-right" uiTransform={{ width: 88 }} height={ROW} />
|
|
26
|
+
</UiEntity>)}
|
|
27
|
+
</UiPanel>
|
|
28
|
+
}, { order: 20 })
|
|
28
29
|
}
|
|
@@ -49,7 +49,7 @@ export class Leaderboard {
|
|
|
49
49
|
if (isServer()) { return }
|
|
50
50
|
if (this.display === '2D UI') {
|
|
51
51
|
VisibilityComponent.createOrReplace(this.entity, { visible: false, propagateToChildren: true })
|
|
52
|
-
mountLeaderboardHud(this.
|
|
52
|
+
mountLeaderboardHud(this.position, () => this.content())
|
|
53
53
|
return
|
|
54
54
|
}
|
|
55
55
|
this.panel = this.findPanel()
|
|
@@ -31,8 +31,9 @@ Configure the placed script, with one distinct courseId per course:
|
|
|
31
31
|
- `collectibleAreas`: comma-separated Trigger Area names, each counts once per player.
|
|
32
32
|
- `accentColor`: fallback six-digit hex color. Place UI Theme to style the entire scene together.
|
|
33
33
|
- `collectibleVisuals`: comma-separated names of plain visual entities, matching collectibleAreas in order.
|
|
34
|
-
- `hud`: "Full" (run panel
|
|
35
|
-
|
|
34
|
+
- `hud`: "Full" (run panel and health on the left, clock and Restart on the right),
|
|
35
|
+
"Big timer" (one large clock at the top centre plus Restart and the results screen)
|
|
36
|
+
or "Hidden" (draws nothing). Both use the shared HUD layout and fit phones.
|
|
36
37
|
The creator's HUD request is THIS setting: "one big timer" = "Big timer". For a
|
|
37
38
|
custom HUD set "Hidden" and read `runOf()`; never draw a second clock beside it.
|
|
38
39
|
|
|
@@ -14,8 +14,12 @@
|
|
|
14
14
|
"restart"
|
|
15
15
|
],
|
|
16
16
|
"requiresSdk": "auth-server",
|
|
17
|
-
"version": "1.
|
|
17
|
+
"version": "1.4.0",
|
|
18
18
|
"changelog": [
|
|
19
|
+
{
|
|
20
|
+
"version": "1.4.0",
|
|
21
|
+
"notes": "The run HUD fits phones: Restart moves from the bottom-right corner (under the jump button) to under the clock, panels stack in the shared HUD layout instead of overlapping other HUDs, the controls hint matches the device, and the completion screen hides the touch controls while it is open."
|
|
22
|
+
},
|
|
19
23
|
{
|
|
20
24
|
"version": "1.3.1",
|
|
21
25
|
"notes": "Hit points show unless Health & Respawn's Health Bar is turned off, so older Health & Respawn copies keep their bar."
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import ReactEcs, { ReactEcsRenderer } from '@dcl/sdk/react-ecs'
|
|
2
1
|
import { engine, PlayerIdentityData, VisibilityComponent, type Entity } from '@dcl/sdk/ecs'
|
|
3
2
|
import { isServer } from '@dcl/sdk/network'
|
|
4
3
|
import { game, reportProblem } from '~runtime/game'
|
|
5
|
-
import {
|
|
6
|
-
import { UI_CANVAS } from '~runtime/uiTheme'
|
|
4
|
+
import { mountRunHud, type RunHudProps } from '~runtime/gameHud'
|
|
7
5
|
import type { ColorHex, EntityName, EntityNames, ZoneName, ZoneNames } from '~runtime/authoring'
|
|
8
6
|
import { createRun, restartRun, runOf } from '~runtime/runs'
|
|
9
7
|
import { entityWorld, namedEntity } from '~runtime/sceneNames'
|
|
@@ -101,7 +99,7 @@ export class RunProgress {
|
|
|
101
99
|
watch(this.finishArea, { type: 'finish' })
|
|
102
100
|
this.points.forEach((area, index) => watch(area, { type: 'checkpoint', index }))
|
|
103
101
|
this.items.forEach((id) => watch(id, { type: 'collect', id }))
|
|
104
|
-
if (this.hud !== 'Hidden')
|
|
102
|
+
if (this.hud !== 'Hidden') mountRunHud(() => this.hudProps())
|
|
105
103
|
}
|
|
106
104
|
|
|
107
105
|
update(): void {
|
|
@@ -150,21 +148,21 @@ export class RunProgress {
|
|
|
150
148
|
}).finally(() => { this.pending = false })
|
|
151
149
|
}
|
|
152
150
|
|
|
153
|
-
private
|
|
151
|
+
private hudProps(): RunHudProps {
|
|
154
152
|
const player = this.player()
|
|
155
153
|
const state = this.current() ?? freshRun()
|
|
156
154
|
const health = game.state.healthBar === false ? null : record(game.state.health)[player]
|
|
157
155
|
const life = record(record(game.state.healthLife)[player])
|
|
158
|
-
return
|
|
159
|
-
title
|
|
160
|
-
elapsedMs
|
|
161
|
-
checkpoint
|
|
162
|
-
collected
|
|
163
|
-
health
|
|
164
|
-
maxHealth
|
|
165
|
-
respawnSeconds
|
|
166
|
-
notice
|
|
167
|
-
accentColor
|
|
168
|
-
|
|
156
|
+
return {
|
|
157
|
+
title: this.title, objective: this.objective, phase: state.phase,
|
|
158
|
+
elapsedMs: elapsedRun(state, game.now()), bestMs: state.bestMs,
|
|
159
|
+
checkpoint: state.checkpoint, checkpoints: this.points.length,
|
|
160
|
+
collected: state.collected.length, collectibles: this.items.length,
|
|
161
|
+
health: typeof health === 'number' ? health : null,
|
|
162
|
+
maxHealth: typeof game.state.healthMax === 'number' ? game.state.healthMax : 100,
|
|
163
|
+
respawnSeconds: life.dead === true && typeof life.respawnAt === 'number' ? Math.max(0, life.respawnAt - game.now()) / 1000 : 0,
|
|
164
|
+
notice: game.now() < this.noticeUntil ? this.notice : '',
|
|
165
|
+
accentColor: this.accentColor, restart: () => this.restart(), hud: this.hud === 'Big timer' ? 'Big timer' : 'Full'
|
|
166
|
+
}
|
|
169
167
|
}
|
|
170
168
|
}
|
|
@@ -40,8 +40,8 @@ Params of the prefab's script — set them in the placePrefab request:
|
|
|
40
40
|
- position: where the 2D overlay sits — 'top' (default), 'top left', 'top right'
|
|
41
41
|
or 'bottom'. Ignored for '3D text'.
|
|
42
42
|
|
|
43
|
-
The overlay uses UI Theme
|
|
44
|
-
|
|
43
|
+
The overlay uses UI Theme and the shared HUD layout: HUDs in the same position
|
|
44
|
+
stack instead of overlapping. Multiple placed clocks keep their own label and time.
|
|
45
45
|
|
|
46
46
|
## Shared deadlines
|
|
47
47
|
|
|
@@ -11,8 +11,12 @@
|
|
|
11
11
|
"time"
|
|
12
12
|
],
|
|
13
13
|
"requiresSdk": "auth-server",
|
|
14
|
-
"version": "1.
|
|
14
|
+
"version": "1.2.0",
|
|
15
15
|
"changelog": [
|
|
16
|
+
{
|
|
17
|
+
"version": "1.2.0",
|
|
18
|
+
"notes": "The 2D clock takes its place in the shared HUD layout, so it no longer overlaps other HUDs on any screen."
|
|
19
|
+
},
|
|
16
20
|
{
|
|
17
21
|
"version": "1.0.0",
|
|
18
22
|
"notes": "Initial release: the Multiplayer Server's NTP-synced time, identical for every player, shown as 3D text at the item or as a 2D overlay on the player's client."
|
|
@@ -35,7 +35,7 @@ export class ServerClock {
|
|
|
35
35
|
if (this.onScreen) {
|
|
36
36
|
VisibilityComponent.createOrReplace(this.entity, { visible: false })
|
|
37
37
|
TextShape.deleteFrom(this.entity)
|
|
38
|
-
mountStatusHud(this.
|
|
38
|
+
mountStatusHud(this.position, () => ({ label: this.label, value: this.time }))
|
|
39
39
|
}
|
|
40
40
|
this.render('--:--:--')
|
|
41
41
|
}
|
package/prefabs/ui-theme/ai.md
CHANGED
|
@@ -13,13 +13,15 @@ Place one UI Theme from the library. Pick Accent Color and Dark or Light in its
|
|
|
13
13
|
- `accentColor`: six-digit hex color, edited with a color picker.
|
|
14
14
|
- `appearance`: Dark or Light.
|
|
15
15
|
|
|
16
|
-
For custom UI, import `sceneUiTheme`
|
|
16
|
+
For custom UI, import `sceneUiTheme` from `~runtime/uiTheme`, `UiPanel`, `UiText`, `UiButton`, `ProgressPips`, `UiNotice` from `~runtime/uiComponents`, and place every panel with `addHudItem(slot, render)` from `~runtime/hudLayout` (its header documents the slots) instead of `ReactEcsRenderer.addUiRenderer`. Each panel declares width and height and is at most `HUD_COLUMN_WIDTH` wide; handlers go on actual buttons. Inspect a screenshot in the real preview, including completion.
|
|
17
17
|
|
|
18
18
|
`ColorHex`, `EntityName`, `EntityNames`, `ZoneName` and `ZoneNames` from `~runtime/authoring` are string aliases that give constructor parameters color or entity pickers. Plural references are ordered comma-separated names; creators pick and reorder them in the inspector. Names must be unique and contain no commas. The assistant can provide arrays to the plural parameters.
|
|
19
19
|
|
|
20
20
|
## Do / Don't
|
|
21
21
|
|
|
22
|
-
- Use one theme per scene, readable text and small non-blocking HUDs.
|
|
22
|
+
- Use one theme per scene, readable text (16 px or more) and small non-blocking HUDs.
|
|
23
|
+
- Never put UI in the bottom corners or the screen's left edge: phones draw the joystick and the jump/E/F buttons there. Results, shops and rule cards use the `modal` slot, which hides the touch controls while open.
|
|
24
|
+
- No hover-only states and no emoji in text; buttons at least 48 px tall.
|
|
23
25
|
- Do not write a separate palette for each prefab or use default pink SDK buttons.
|
|
24
26
|
- Verify running and finished states in a real preview screenshot.
|
|
25
27
|
|
|
@@ -11,8 +11,12 @@
|
|
|
11
11
|
"hud",
|
|
12
12
|
"design"
|
|
13
13
|
],
|
|
14
|
-
"version": "1.
|
|
14
|
+
"version": "1.1.0",
|
|
15
15
|
"changelog": [
|
|
16
|
+
{
|
|
17
|
+
"version": "1.1.0",
|
|
18
|
+
"notes": "Custom HUDs are placed through the shared HUD layout, which keeps them clear of the phone touch controls and of each other."
|
|
19
|
+
},
|
|
16
20
|
{
|
|
17
21
|
"version": "1.0.0",
|
|
18
22
|
"notes": "One accent color and dark or light appearance shared by the scene's game HUDs, buttons, timers, leaderboards and results."
|