@dcl-regenesislabs/web-editor 0.0.0-stage → 0.1.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/editor.css +1 -0
- package/editor.js +33891 -0
- package/package.json +8 -4
- package/prefabs/admin-tools/composite.json +77 -0
- package/prefabs/admin-tools/data.json +28 -0
- package/prefabs/admin-tools/icons/admin-panel-control-button.png +0 -0
- package/prefabs/admin-tools/icons/admin-panel-moderation-control-button.png +0 -0
- package/prefabs/admin-tools/icons/admin-panel-rewards-control-button.png +0 -0
- package/prefabs/admin-tools/icons/admin-panel-smart-item-control-button.png +0 -0
- package/prefabs/admin-tools/icons/admin-panel-text-announcement-control-button.png +0 -0
- package/prefabs/admin-tools/icons/admin-panel-video-control-button.png +0 -0
- package/prefabs/admin-tools/icons/admin-tool-background.png +0 -0
- package/prefabs/admin-tools/icons/announcements/text-announcement-chat-message.png +0 -0
- package/prefabs/admin-tools/icons/announcements/text-announcement-check.png +0 -0
- package/prefabs/admin-tools/icons/announcements/text-announcement-close-button.png +0 -0
- package/prefabs/admin-tools/icons/moderation/admin-panel-verified-user.png +0 -0
- package/prefabs/admin-tools/icons/moderation/ban.png +0 -0
- package/prefabs/admin-tools/icons/moderation/chevron-back.png +0 -0
- package/prefabs/admin-tools/icons/moderation/chevron-forward.png +0 -0
- package/prefabs/admin-tools/icons/moderation/close.png +0 -0
- package/prefabs/admin-tools/icons/moderation/error.png +0 -0
- package/prefabs/admin-tools/icons/moderation/person-outline.png +0 -0
- package/prefabs/admin-tools/icons/moderation-control-icon.png +0 -0
- package/prefabs/admin-tools/icons/rewards/close.png +0 -0
- package/prefabs/admin-tools/icons/rewards/send.png +0 -0
- package/prefabs/admin-tools/icons/rewards-control.png +0 -0
- package/prefabs/admin-tools/icons/smart-item-control.png +0 -0
- package/prefabs/admin-tools/icons/text-announcement-control.png +0 -0
- package/prefabs/admin-tools/icons/video/chevron-down.png +0 -0
- package/prefabs/admin-tools/icons/video/chevron-up.png +0 -0
- package/prefabs/admin-tools/icons/video/copy-to-clipboard.png +0 -0
- package/prefabs/admin-tools/icons/video/error.png +0 -0
- package/prefabs/admin-tools/icons/video/eye-off.png +0 -0
- package/prefabs/admin-tools/icons/video/eye.png +0 -0
- package/prefabs/admin-tools/icons/video/help.png +0 -0
- package/prefabs/admin-tools/icons/video/info.png +0 -0
- package/prefabs/admin-tools/icons/video/person-outline.png +0 -0
- package/prefabs/admin-tools/icons/video/star.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-dcl-cast.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-live.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-loop.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-mute.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-pause-button.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-play-button.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-video-icon.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-volume-minus-button.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-volume-plus-button.png +0 -0
- package/prefabs/admin-tools/icons/video-control.png +0 -0
- package/prefabs/admin-tools/scripts/actions.ts +206 -0
- package/prefabs/admin-tools/scripts/admin.tsx +253 -0
- package/prefabs/admin-tools/scripts/api.ts +125 -0
- package/prefabs/admin-tools/scripts/components.ts +190 -0
- package/prefabs/admin-tools/scripts/icons.ts +53 -0
- package/prefabs/admin-tools/scripts/message-bus.ts +297 -0
- package/prefabs/admin-tools/scripts/state.ts +69 -0
- package/prefabs/admin-tools/scripts/tabs/Moderation.tsx +155 -0
- package/prefabs/admin-tools/scripts/tabs/Rewards.tsx +136 -0
- package/prefabs/admin-tools/scripts/tabs/SmartItemActions.tsx +167 -0
- package/prefabs/admin-tools/scripts/tabs/TextAnnouncements.tsx +195 -0
- package/prefabs/admin-tools/scripts/tabs/VideoControl.tsx +156 -0
- package/prefabs/admin-tools/scripts/tabs/announcements/Overlay.tsx +94 -0
- package/prefabs/admin-tools/scripts/tabs/announcements/icons.ts +15 -0
- package/prefabs/admin-tools/scripts/tabs/announcements/state.ts +71 -0
- package/prefabs/admin-tools/scripts/tabs/announcements/ui.tsx +37 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/AddUserInput.tsx +184 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/RemoveAdminConfirmation.tsx +93 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/UsersList.tsx +228 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/api.ts +35 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/icons.ts +23 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/kick.ts +95 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/state.ts +69 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/ui.tsx +172 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/utils.ts +88 -0
- package/prefabs/admin-tools/scripts/tabs/rewards/Button.tsx +52 -0
- package/prefabs/admin-tools/scripts/tabs/rewards/Captcha.tsx +88 -0
- package/prefabs/admin-tools/scripts/tabs/rewards/api.ts +138 -0
- package/prefabs/admin-tools/scripts/tabs/rewards/claim.ts +99 -0
- package/prefabs/admin-tools/scripts/tabs/rewards/controller.ts +103 -0
- package/prefabs/admin-tools/scripts/tabs/rewards/icons.ts +13 -0
- package/prefabs/admin-tools/scripts/tabs/rewards/state.ts +32 -0
- package/prefabs/admin-tools/scripts/tabs/smart-items/selection.ts +90 -0
- package/prefabs/admin-tools/scripts/tabs/video/DclCast.tsx +226 -0
- package/prefabs/admin-tools/scripts/tabs/video/LiveStream.tsx +284 -0
- package/prefabs/admin-tools/scripts/tabs/video/SpeakerShowcase.tsx +112 -0
- package/prefabs/admin-tools/scripts/tabs/video/VideoUrl.tsx +107 -0
- package/prefabs/admin-tools/scripts/tabs/video/Volume.tsx +69 -0
- package/prefabs/admin-tools/scripts/tabs/video/api.ts +172 -0
- package/prefabs/admin-tools/scripts/tabs/video/controls.ts +108 -0
- package/prefabs/admin-tools/scripts/tabs/video/icons.ts +59 -0
- package/prefabs/admin-tools/scripts/tabs/video/speakers.ts +43 -0
- package/prefabs/admin-tools/scripts/tabs/video/state.ts +82 -0
- package/prefabs/admin-tools/scripts/tabs/video/ui.tsx +243 -0
- package/prefabs/admin-tools/scripts/types.ts +46 -0
- package/prefabs/admin-tools/scripts/ui.tsx +122 -0
- package/prefabs/admin-tools/thumbnail.png +0 -0
- package/prefabs/announcer/ai.md +76 -0
- package/prefabs/announcer/composite.json +31 -0
- package/prefabs/announcer/data.json +35 -0
- package/prefabs/announcer/scripts/announcer.tsx +79 -0
- package/prefabs/announcer/scripts/pure/toast.ts +30 -0
- package/prefabs/announcer/thumbnail.png +0 -0
- package/prefabs/black-chair/HighBackChair.glb +0 -0
- package/prefabs/black-chair/composite.json +74 -0
- package/prefabs/black-chair/data.json +30 -0
- package/prefabs/black-chair/scripts/seat.ts +191 -0
- package/prefabs/black-chair/thumbnail.png +0 -0
- package/prefabs/catalog.json +1 -0
- package/prefabs/classic-bench/Bench_01.glb +0 -0
- package/prefabs/classic-bench/composite.json +100 -0
- package/prefabs/classic-bench/data.json +34 -0
- package/prefabs/classic-bench/file1.png +0 -0
- package/prefabs/classic-bench/scripts/seat.ts +191 -0
- package/prefabs/classic-bench/thumbnail.png +0 -0
- package/prefabs/classic-bench-armrests/Bench 1.glb +0 -0
- package/prefabs/classic-bench-armrests/composite.json +100 -0
- package/prefabs/classic-bench-armrests/data.json +30 -0
- package/prefabs/classic-bench-armrests/scripts/seat.ts +191 -0
- package/prefabs/classic-bench-armrests/thumbnail.png +0 -0
- package/prefabs/classroom-chair/Chair_02.glb +0 -0
- package/prefabs/classroom-chair/composite.json +74 -0
- package/prefabs/classroom-chair/data.json +34 -0
- package/prefabs/classroom-chair/file1.png +0 -0
- package/prefabs/classroom-chair/scripts/seat.ts +191 -0
- package/prefabs/classroom-chair/thumbnail.png +0 -0
- package/prefabs/court-chair/Chair_Wood_01.glb +0 -0
- package/prefabs/court-chair/FanstasyPack_TX.png +0 -0
- package/prefabs/court-chair/composite.json +74 -0
- package/prefabs/court-chair/data.json +34 -0
- package/prefabs/court-chair/scripts/seat.ts +191 -0
- package/prefabs/court-chair/thumbnail.png +0 -0
- package/prefabs/curved-couch/CurvedCouch.glb +0 -0
- package/prefabs/curved-couch/composite.json +100 -0
- package/prefabs/curved-couch/data.json +30 -0
- package/prefabs/curved-couch/scripts/seat.ts +191 -0
- package/prefabs/curved-couch/thumbnail.png +0 -0
- package/prefabs/game-flow/ai.md +94 -0
- package/prefabs/game-flow/composite.json +45 -0
- package/prefabs/game-flow/data.json +27 -0
- package/prefabs/game-flow/scripts/game-flow.ts +168 -0
- package/prefabs/game-flow/scripts/pure/flow.ts +185 -0
- package/prefabs/game-flow/thumbnail.png +0 -0
- package/prefabs/health-respawn/ai.md +76 -0
- package/prefabs/health-respawn/composite.json +31 -0
- package/prefabs/health-respawn/data.json +38 -0
- package/prefabs/health-respawn/scripts/health-respawn.ts +98 -0
- package/prefabs/health-respawn/scripts/health.ts +22 -0
- package/prefabs/health-respawn/scripts/pure/health.ts +60 -0
- package/prefabs/health-respawn/thumbnail.png +0 -0
- package/prefabs/high-stool/HighStool.glb +0 -0
- package/prefabs/high-stool/composite.json +74 -0
- package/prefabs/high-stool/data.json +30 -0
- package/prefabs/high-stool/scripts/seat.ts +191 -0
- package/prefabs/high-stool/thumbnail.png +0 -0
- package/prefabs/large-couch/ThreeSeater_Couch.glb +0 -0
- package/prefabs/large-couch/composite.json +100 -0
- package/prefabs/large-couch/data.json +30 -0
- package/prefabs/large-couch/scripts/seat.ts +191 -0
- package/prefabs/large-couch/thumbnail.png +0 -0
- package/prefabs/leaderboard/ai.md +75 -0
- package/prefabs/leaderboard/board-panel.glb +0 -0
- package/prefabs/leaderboard/composite.json +82 -0
- package/prefabs/leaderboard/data.json +35 -0
- package/prefabs/leaderboard/scripts/leaderboard.ts +66 -0
- package/prefabs/leaderboard/scripts/pure/board.ts +71 -0
- package/prefabs/leaderboard/thumbnail.png +0 -0
- package/prefabs/loveseat/Couch_01.glb +0 -0
- package/prefabs/loveseat/composite.json +100 -0
- package/prefabs/loveseat/data.json +34 -0
- package/prefabs/loveseat/file1.png +0 -0
- package/prefabs/loveseat/scripts/seat.ts +191 -0
- package/prefabs/loveseat/thumbnail.png +0 -0
- package/prefabs/modern-sofa/ModernSofa.glb +0 -0
- package/prefabs/modern-sofa/composite.json +100 -0
- package/prefabs/modern-sofa/data.json +30 -0
- package/prefabs/modern-sofa/scripts/seat.ts +191 -0
- package/prefabs/modern-sofa/thumbnail.png +0 -0
- package/prefabs/outdoor-chair/Chair_07.glb +0 -0
- package/prefabs/outdoor-chair/composite.json +74 -0
- package/prefabs/outdoor-chair/data.json +34 -0
- package/prefabs/outdoor-chair/file1.png +0 -0
- package/prefabs/outdoor-chair/scripts/seat.ts +191 -0
- package/prefabs/outdoor-chair/thumbnail.png +0 -0
- package/prefabs/rustic-bench/Bench_01.glb +0 -0
- package/prefabs/rustic-bench/PiratesPack_TX.png.png +0 -0
- package/prefabs/rustic-bench/composite.json +100 -0
- package/prefabs/rustic-bench/data.json +34 -0
- package/prefabs/rustic-bench/scripts/seat.ts +191 -0
- package/prefabs/rustic-bench/thumbnail.png +0 -0
- package/prefabs/rustic-round-stool/Chairwood_01.glb +0 -0
- package/prefabs/rustic-round-stool/PiratesPack_TX.png.png +0 -0
- package/prefabs/rustic-round-stool/composite.json +74 -0
- package/prefabs/rustic-round-stool/data.json +34 -0
- package/prefabs/rustic-round-stool/scripts/seat.ts +191 -0
- package/prefabs/rustic-round-stool/thumbnail.png +0 -0
- package/prefabs/rustic-square-stool/Chairwood_02.glb +0 -0
- package/prefabs/rustic-square-stool/PiratesPack_TX.png.png +0 -0
- package/prefabs/rustic-square-stool/composite.json +74 -0
- package/prefabs/rustic-square-stool/data.json +34 -0
- package/prefabs/rustic-square-stool/scripts/seat.ts +191 -0
- package/prefabs/rustic-square-stool/thumbnail.png +0 -0
- package/prefabs/server-clock/ai.md +67 -0
- package/prefabs/server-clock/composite.json +45 -0
- package/prefabs/server-clock/data.json +24 -0
- package/prefabs/server-clock/scripts/clock-hud.tsx +55 -0
- package/prefabs/server-clock/scripts/server-clock.ts +71 -0
- package/prefabs/server-clock/thumbnail.png +0 -0
- package/prefabs/simple-chair/Chair_03.glb +0 -0
- package/prefabs/simple-chair/composite.json +74 -0
- package/prefabs/simple-chair/data.json +34 -0
- package/prefabs/simple-chair/file1.png +0 -0
- package/prefabs/simple-chair/scripts/seat.ts +191 -0
- package/prefabs/simple-chair/thumbnail.png +0 -0
- package/prefabs/sit-spot/composite.json +45 -0
- package/prefabs/sit-spot/data.json +30 -0
- package/prefabs/sit-spot/scripts/seat.ts +191 -0
- package/prefabs/sit-spot/thumbnail.png +0 -0
- package/prefabs/sit-spot-edge/composite.json +42 -0
- package/prefabs/sit-spot-edge/data.json +32 -0
- package/prefabs/sit-spot-edge/emotes/Sit_Edge1_emote.glb +0 -0
- package/prefabs/sit-spot-edge/emotes/Sit_Edge2_emote.glb +0 -0
- package/prefabs/sit-spot-edge/scripts/seat.ts +191 -0
- package/prefabs/sit-spot-edge/thumbnail.png +0 -0
- package/prefabs/small-couch/TwoSeater_Couch.glb +0 -0
- package/prefabs/small-couch/composite.json +100 -0
- package/prefabs/small-couch/data.json +30 -0
- package/prefabs/small-couch/scripts/seat.ts +191 -0
- package/prefabs/small-couch/thumbnail.png +0 -0
- package/prefabs/spawner/ai.md +109 -0
- package/prefabs/spawner/composite.json +73 -0
- package/prefabs/spawner/data.json +22 -0
- package/prefabs/spawner/scripts/spawner.ts +380 -0
- package/prefabs/spawner/thumbnail.png +0 -0
- package/prefabs/steampunk-bench/Steampunk Bench.glb +0 -0
- package/prefabs/steampunk-bench/composite.json +100 -0
- package/prefabs/steampunk-bench/data.json +30 -0
- package/prefabs/steampunk-bench/scripts/seat.ts +191 -0
- package/prefabs/steampunk-bench/thumbnail.png +0 -0
- package/prefabs/steampunk-chair/Steampunk Chair.glb +0 -0
- package/prefabs/steampunk-chair/composite.json +74 -0
- package/prefabs/steampunk-chair/data.json +30 -0
- package/prefabs/steampunk-chair/scripts/seat.ts +191 -0
- package/prefabs/steampunk-chair/thumbnail.png +0 -0
- package/prefabs/tall-stool/Stool_D.glb +0 -0
- package/prefabs/tall-stool/composite.json +74 -0
- package/prefabs/tall-stool/data.json +30 -0
- package/prefabs/tall-stool/scripts/seat.ts +191 -0
- package/prefabs/tall-stool/thumbnail.png +0 -0
- package/prefabs/trigger-zone/ai.md +115 -0
- package/prefabs/trigger-zone/composite.json +52 -0
- package/prefabs/trigger-zone/data.json +31 -0
- package/prefabs/trigger-zone/scripts/trigger-zone.ts +89 -0
- package/prefabs/trigger-zone/thumbnail.png +0 -0
- package/prefabs/video-screen/composite.json +98 -0
- package/prefabs/video-screen/data.json +21 -0
- package/prefabs/video-screen/thumbnail.png +0 -0
- package/prefabs/video-screen/video_player.glb +0 -0
- package/prefabs/wooden-chair/Chair 1.glb +0 -0
- package/prefabs/wooden-chair/composite.json +74 -0
- package/prefabs/wooden-chair/data.json +30 -0
- package/prefabs/wooden-chair/scripts/seat.ts +191 -0
- package/prefabs/wooden-chair/thumbnail.png +0 -0
- package/prefabs/wooden-chair-armrests/Chair 3.glb +0 -0
- package/prefabs/wooden-chair-armrests/composite.json +74 -0
- package/prefabs/wooden-chair-armrests/data.json +30 -0
- package/prefabs/wooden-chair-armrests/scripts/seat.ts +191 -0
- package/prefabs/wooden-chair-armrests/thumbnail.png +0 -0
- package/scene/about +17 -0
- package/scene/bafkreias2w4xuqaic6sdcvblrisayi6xg7drfowzpt5ubjkmrk3mx6czc4 +1 -0
- package/scene/bafkreiby2gmthtauf7cckttphmhpecsueyypi2hzlke4lcodg7fm4cm2sq +23 -0
- package/scene/bafkreidhwqwajqk4nsuffef5fkdrgmp5ql6vnn2knpqsuqalyosv5o6lk4 +1 -0
- package/scene/bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku +0 -0
- package/scene/bafybeihw3xlbff4sf5sc3kvmlmlwf2visnty5lfymawlunzt5vrkp5fd7u +90 -0
- package/web-build/esbuild.wasm +0 -0
- package/web-build/index.js +3 -0
- package/web-build/sdk-snapshot.json +1 -0
- package/web-build/worker.js +701 -0
- package/README.md +0 -3
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// Sit on this seat: click a sit spot -> the avatar is placed on it facing forward
|
|
2
|
+
// and a looping sitting emote plays; moving cancels the emote engine-side (the
|
|
3
|
+
// same mechanism the Creator Hub's seat smart items and Genesis Plaza use — no
|
|
4
|
+
// avatar attach). Spots are child entities named "Sit Spot…" carrying only a
|
|
5
|
+
// Transform; this script gives them their collider and pointer event at runtime.
|
|
6
|
+
// With no such children (the standalone Sit Spot prefab), the entity itself is
|
|
7
|
+
// the spot.
|
|
8
|
+
import {
|
|
9
|
+
ColliderLayer,
|
|
10
|
+
InputAction,
|
|
11
|
+
Material,
|
|
12
|
+
MeshCollider,
|
|
13
|
+
MeshRenderer,
|
|
14
|
+
Schemas,
|
|
15
|
+
Transform,
|
|
16
|
+
VisibilityComponent,
|
|
17
|
+
engine,
|
|
18
|
+
pointerEventsSystem,
|
|
19
|
+
type Entity,
|
|
20
|
+
type LastWriteWinElementSetComponentDefinition
|
|
21
|
+
} from '@dcl/sdk/ecs'
|
|
22
|
+
import { Quaternion, Vector3 } from '@dcl/sdk/math'
|
|
23
|
+
import { isServer } from '@dcl/sdk/network'
|
|
24
|
+
import { movePlayerTo, triggerEmote, triggerSceneEmote } from '~system/RestrictedActions'
|
|
25
|
+
|
|
26
|
+
const SPOT_NAME_PREFIX = 'sit spot'
|
|
27
|
+
const HOVER_TEXT = 'Sit Here'
|
|
28
|
+
const MAX_DISTANCE = 6
|
|
29
|
+
const EMOTE_DELAY_S = 0.25
|
|
30
|
+
const SITTING_EMOTES = ['sittingChair1', 'sittingChair2']
|
|
31
|
+
// emote .glb files bundled in this prefab's folder (Genesis Plaza-style custom
|
|
32
|
+
// poses, played via triggerSceneEmote); empty = the predefined chair emotes
|
|
33
|
+
const SCENE_EMOTES: string[] = []
|
|
34
|
+
|
|
35
|
+
// the Plaza-style "you can sit here" hint: a small glowing dot floating over
|
|
36
|
+
// each free spot, pulsing gently, shown only to nearby players
|
|
37
|
+
const DOT_VISIBLE_DIST = 10
|
|
38
|
+
const DOT_OCCUPIED_DIST = 0.9
|
|
39
|
+
const DOT_HEIGHT = 0.55
|
|
40
|
+
const DOT_SIZE = 0.09
|
|
41
|
+
const DOT_PULSE = 0.25
|
|
42
|
+
|
|
43
|
+
type NameValue = { value: string }
|
|
44
|
+
type NameComponent = LastWriteWinElementSetComponentDefinition<NameValue>
|
|
45
|
+
|
|
46
|
+
// Every placed seat prefab bundles its own copy of this script (prefab folders are
|
|
47
|
+
// self-contained), so the component may already be defined by a sibling copy.
|
|
48
|
+
function nameComponent(): NameComponent {
|
|
49
|
+
const existing = engine.getComponentOrNull('core-schema::Name')
|
|
50
|
+
if (existing !== null) return existing as NameComponent
|
|
51
|
+
return engine.defineComponent('core-schema::Name', { value: Schemas.String })
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isSpotName(name: unknown): boolean {
|
|
55
|
+
return typeof name === 'string' && name.toLowerCase().startsWith(SPOT_NAME_PREFIX)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function sceneRelativeTransform(entity: Entity): { position: Vector3; rotation: Quaternion } {
|
|
59
|
+
const chain: Entity[] = []
|
|
60
|
+
let cursor = entity
|
|
61
|
+
while (cursor !== engine.RootEntity && chain.length < 32) {
|
|
62
|
+
chain.push(cursor)
|
|
63
|
+
const t = Transform.getOrNull(cursor)
|
|
64
|
+
if (t === null) break
|
|
65
|
+
cursor = t.parent ?? engine.RootEntity
|
|
66
|
+
}
|
|
67
|
+
let position = Vector3.Zero()
|
|
68
|
+
let rotation = Quaternion.Identity()
|
|
69
|
+
let scale = Vector3.One()
|
|
70
|
+
for (const link of chain.reverse()) {
|
|
71
|
+
const t = Transform.getOrNull(link)
|
|
72
|
+
if (t === null) continue
|
|
73
|
+
const local = Vector3.create(
|
|
74
|
+
t.position.x * scale.x,
|
|
75
|
+
t.position.y * scale.y,
|
|
76
|
+
t.position.z * scale.z
|
|
77
|
+
)
|
|
78
|
+
position = Vector3.add(position, Vector3.rotate(local, rotation))
|
|
79
|
+
rotation = Quaternion.multiply(rotation, t.rotation)
|
|
80
|
+
scale = Vector3.create(scale.x * t.scale.x, scale.y * t.scale.y, scale.z * t.scale.z)
|
|
81
|
+
}
|
|
82
|
+
return { position, rotation }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export class Seat {
|
|
86
|
+
private emoteIn = 0
|
|
87
|
+
private time = 0
|
|
88
|
+
private dots: Array<{ spot: Entity; dot: Entity; visible: boolean }> = []
|
|
89
|
+
|
|
90
|
+
constructor(
|
|
91
|
+
public src: string,
|
|
92
|
+
public entity: Entity
|
|
93
|
+
) {}
|
|
94
|
+
|
|
95
|
+
start(): void {
|
|
96
|
+
if (isServer()) { return }
|
|
97
|
+
const Name = nameComponent()
|
|
98
|
+
const spots: Entity[] = []
|
|
99
|
+
for (const [child, transform] of engine.getEntitiesWith(Transform)) {
|
|
100
|
+
if (transform.parent !== this.entity) continue
|
|
101
|
+
const name = Name.getOrNull(child)
|
|
102
|
+
if (name !== null && isSpotName(name.value)) spots.push(child)
|
|
103
|
+
}
|
|
104
|
+
if (spots.length === 0) spots.push(this.entity)
|
|
105
|
+
|
|
106
|
+
for (const spot of spots) {
|
|
107
|
+
MeshCollider.setBox(spot, ColliderLayer.CL_POINTER)
|
|
108
|
+
pointerEventsSystem.onPointerDown(
|
|
109
|
+
{
|
|
110
|
+
entity: spot,
|
|
111
|
+
opts: { button: InputAction.IA_POINTER, hoverText: HOVER_TEXT, maxDistance: MAX_DISTANCE }
|
|
112
|
+
},
|
|
113
|
+
() => this.sit(spot)
|
|
114
|
+
)
|
|
115
|
+
// no collider on the dot: clicks pass through to the spot beneath it
|
|
116
|
+
const dot = engine.addEntity()
|
|
117
|
+
Transform.create(dot, {
|
|
118
|
+
parent: spot,
|
|
119
|
+
position: Vector3.create(0, DOT_HEIGHT, 0),
|
|
120
|
+
scale: Vector3.create(DOT_SIZE, DOT_SIZE, DOT_SIZE)
|
|
121
|
+
})
|
|
122
|
+
MeshRenderer.setSphere(dot)
|
|
123
|
+
Material.setPbrMaterial(dot, {
|
|
124
|
+
albedoColor: { r: 1, g: 1, b: 1, a: 0.85 },
|
|
125
|
+
emissiveColor: { r: 1, g: 1, b: 1 },
|
|
126
|
+
emissiveIntensity: 2,
|
|
127
|
+
roughness: 1
|
|
128
|
+
})
|
|
129
|
+
VisibilityComponent.create(dot, { visible: false })
|
|
130
|
+
this.dots.push({ spot, dot, visible: false })
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
update(dt: number): void {
|
|
135
|
+
// The hint walks a transform chain per spot per frame, and a seat is placed
|
|
136
|
+
// by the dozen: without this the Multiplayer Server pays for every one.
|
|
137
|
+
if (isServer()) { return }
|
|
138
|
+
this.time += dt
|
|
139
|
+
this.updateDots()
|
|
140
|
+
if (this.emoteIn <= 0) return
|
|
141
|
+
this.emoteIn -= dt
|
|
142
|
+
if (this.emoteIn > 0) return
|
|
143
|
+
if (SCENE_EMOTES.length > 0) {
|
|
144
|
+
// src is the script's directory (custom/<slug>/scripts) — the emotes live
|
|
145
|
+
// one level up, in the placed prefab's own folder
|
|
146
|
+
const root = this.src.replace(/\/scripts\/?$/, '')
|
|
147
|
+
const emote = SCENE_EMOTES[Math.floor(Math.random() * SCENE_EMOTES.length)]
|
|
148
|
+
void triggerSceneEmote({ src: `${root}/${emote}`, loop: true })
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
const emote = SITTING_EMOTES[Math.floor(Math.random() * SITTING_EMOTES.length)]
|
|
152
|
+
void triggerEmote({ predefinedEmote: emote })
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private updateDots(): void {
|
|
156
|
+
const player = Transform.getOrNull(engine.PlayerEntity)?.position
|
|
157
|
+
const pulse = 1 + DOT_PULSE * Math.sin(this.time * 3)
|
|
158
|
+
for (const entry of this.dots) {
|
|
159
|
+
let visible = false
|
|
160
|
+
if (player !== undefined) {
|
|
161
|
+
const world = sceneRelativeTransform(entry.spot).position
|
|
162
|
+
const dist = Vector3.distance(player, world)
|
|
163
|
+
// hidden while someone (you) is on the spot — a glow over a seated
|
|
164
|
+
// avatar's head reads as a bug, not a hint
|
|
165
|
+
visible = dist < DOT_VISIBLE_DIST && dist > DOT_OCCUPIED_DIST
|
|
166
|
+
}
|
|
167
|
+
if (entry.visible !== visible) {
|
|
168
|
+
entry.visible = visible
|
|
169
|
+
VisibilityComponent.getMutable(entry.dot).visible = visible
|
|
170
|
+
}
|
|
171
|
+
if (visible) {
|
|
172
|
+
Transform.getMutable(entry.dot).scale = Vector3.create(
|
|
173
|
+
DOT_SIZE * pulse,
|
|
174
|
+
DOT_SIZE * pulse,
|
|
175
|
+
DOT_SIZE * pulse
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private sit(spot: Entity): void {
|
|
182
|
+
const world = sceneRelativeTransform(spot)
|
|
183
|
+
const forward = Vector3.rotate(Vector3.Forward(), world.rotation)
|
|
184
|
+
void movePlayerTo({
|
|
185
|
+
newRelativePosition: world.position,
|
|
186
|
+
avatarTarget: Vector3.add(world.position, forward)
|
|
187
|
+
})
|
|
188
|
+
// let the teleport settle before the emote starts, or the walk cancels it
|
|
189
|
+
this.emoteIn = EMOTE_DELAY_S
|
|
190
|
+
}
|
|
191
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
prefab: trigger-zone
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Trigger Area — AI guide
|
|
6
|
+
|
|
7
|
+
An invisible named volume that knows who is standing in it. Other scripts react
|
|
8
|
+
to it BY NAME through the bus module in the project's shared runtime — nothing is
|
|
9
|
+
wired, and a reacting script pasted into another scene keeps working.
|
|
10
|
+
|
|
11
|
+
## When to use
|
|
12
|
+
|
|
13
|
+
Any request shaped like "when a player walks somewhere / is somewhere / leaves
|
|
14
|
+
somewhere": open a door, play a sound or emote, award points, show a message,
|
|
15
|
+
start an ambience. One area per place — though several volumes may share a Name,
|
|
16
|
+
and the bus then treats them as one place.
|
|
17
|
+
|
|
18
|
+
## API
|
|
19
|
+
|
|
20
|
+
AN AREA'S ID IS THE ENTITY'S NAME, matched trimmed and case-insensitively — the
|
|
21
|
+
[Scene] block lists the areas the scene already has.
|
|
22
|
+
|
|
23
|
+
Import from the project's shared runtime, the one place every runtime module lives:
|
|
24
|
+
|
|
25
|
+
import { isInZone, onZone, playersInZone, zoneOf } from './runtime/zoneBus'
|
|
26
|
+
|
|
27
|
+
- isInZone(name): true while THIS viewer is inside. Occupancy — the default you want.
|
|
28
|
+
- playersInZone(name): every avatar currently inside, deduped across volumes sharing the name.
|
|
29
|
+
- onZone(name, 'enter' | 'exit' | 'any', fn): edges derived from occupancy; returns
|
|
30
|
+
an unsubscribe. Late subscribers get current occupancy replayed as enters. The
|
|
31
|
+
event: { zone, kind, entity (the avatar that MOVED — never the area), address,
|
|
32
|
+
local (true for this viewer), zoneEntity }.
|
|
33
|
+
- zoneOf(entity): the area name of the entity a script is attached to ('' if unnamed).
|
|
34
|
+
|
|
35
|
+
Full signatures (and zoneNames()) are in the module header: src/scripts/runtime/zoneBus.ts.
|
|
36
|
+
|
|
37
|
+
Params of the area's own script — set them in the placePrefab request, never
|
|
38
|
+
tell the user to change them:
|
|
39
|
+
- who: 'this player' (default) | 'any player' — whose client the area reacts to.
|
|
40
|
+
- fireWhen: 'every time' (default) | 'once per player' | 'once ever' — how often
|
|
41
|
+
an entry may fire.
|
|
42
|
+
- exitDelay: seconds (default 0.3) a player may step back out before counting as
|
|
43
|
+
gone. Boundary hysteresis, NOT a cooldown — a reaction owns its own rate limit,
|
|
44
|
+
and naming that limit "cooldown" next to the area's settings reads as this one;
|
|
45
|
+
name it for what it limits and say so in its doc comment.
|
|
46
|
+
|
|
47
|
+
## Occupancy beats edges
|
|
48
|
+
|
|
49
|
+
Most "when someone is in here" code is occupancy, not events: isInZone() in
|
|
50
|
+
update() cannot flicker, needs no debounce, and a door with two people in it
|
|
51
|
+
does not close when one of them leaves.
|
|
52
|
+
|
|
53
|
+
update(): void { if (isInZone('Front Door Area')) this.open(); else this.close() }
|
|
54
|
+
|
|
55
|
+
Use onZone(name, 'enter', …) only when the reaction really is one-shot, 'exit'
|
|
56
|
+
for leaving, 'any' when one script handles both (event.kind is 'enter' | 'exit').
|
|
57
|
+
Cover the edge the user asked for and no more.
|
|
58
|
+
|
|
59
|
+
## Where the reaction script goes
|
|
60
|
+
|
|
61
|
+
An entity's Script component is a LIST — an area carries its detector AND any
|
|
62
|
+
reactions. Decide by what the reaction acts on:
|
|
63
|
+
|
|
64
|
+
- It changes ANOTHER object ("open the door", "turn on the lights") → attach to
|
|
65
|
+
THAT object, resolved from the [Scene] roster, with public zone: string =
|
|
66
|
+
'Front Door Area'. A reaction living elsewhere needs telling which area; never
|
|
67
|
+
hardcode the name where a param would do.
|
|
68
|
+
- It acts on the player, the UI, the sound, the score — nothing else involved
|
|
69
|
+
("play an emote", "show a message", "give points") → attach to THE AREA ITSELF,
|
|
70
|
+
with an attachScript request naming the area, and give it NO zone param at all.
|
|
71
|
+
Not a blank one: a param the creator must leave empty is a field that can only
|
|
72
|
+
be got wrong. Call zoneOf(this.entity) in start() — the attachment already says
|
|
73
|
+
which area, and renaming the area can't orphan it. Exactly this shape, params
|
|
74
|
+
for the reaction only:
|
|
75
|
+
|
|
76
|
+
export class AreaPoints {
|
|
77
|
+
private zone = ''
|
|
78
|
+
constructor(public src: string, public entity: Entity, public points: number = 10) {}
|
|
79
|
+
start() {
|
|
80
|
+
this.zone = zoneOf(this.entity)
|
|
81
|
+
onZone(this.zone, 'enter', (e) => { if (e.local) this.award(e.address) })
|
|
82
|
+
}
|
|
83
|
+
update(dt: number) {}
|
|
84
|
+
private award(address: string) { /* what happens goes here */ }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
- NEVER pick an unrelated entity just to have somewhere to put a script. No
|
|
88
|
+
object involved → the area is the answer.
|
|
89
|
+
- An area named in the prompt ("…when they enter Front Hall") says WHICH area to
|
|
90
|
+
attach to — it is not a request for a zone param.
|
|
91
|
+
|
|
92
|
+
## Do / Don't
|
|
93
|
+
|
|
94
|
+
- DON'T subscribe triggerAreaEventsSystem.onTriggerEnter/Stay/Exit on an area
|
|
95
|
+
entity. The SDK keeps exactly ONE callback per (entity, event), so your
|
|
96
|
+
subscription silently replaces the prefab's own detector and the area stops
|
|
97
|
+
working for everybody. The prefab owns those callbacks; you consume the bus.
|
|
98
|
+
- DON'T hand-roll proximity (distance loops against the player). The prefab
|
|
99
|
+
exists so you never do.
|
|
100
|
+
- The volume IS the entity's Transform scale in metres, so the scale gizmo is the
|
|
101
|
+
resize tool. Neither you nor the editor can measure a model's bounding box —
|
|
102
|
+
place the area NEAR the object at a sensible size and say in one line to drag
|
|
103
|
+
the scale handles to fit. Never claim you fitted it.
|
|
104
|
+
- Detection is client-side only: the headless server has no avatar colliders, so
|
|
105
|
+
an area never fires there. Fine for doors, lights, sound, ambience. When an area
|
|
106
|
+
gates something valuable (a reward, a score, a paid area) put the decision in a
|
|
107
|
+
game.onEnterArea(name, fn) on the server — it re-checks the player's real
|
|
108
|
+
position before it counts — and say in one line that the bus alone is
|
|
109
|
+
client-trusted rather than implying it is safe.
|
|
110
|
+
|
|
111
|
+
## Example
|
|
112
|
+
|
|
113
|
+
"Make the door open when someone walks up": placePrefab trigger-zone named
|
|
114
|
+
"Front Door Area" (4×3×4 at the doorway, who: 'any player'), then a script on
|
|
115
|
+
the Door entity whose update() runs the isInZone snippet above.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"components": [
|
|
4
|
+
{
|
|
5
|
+
"name": "core-schema::Name",
|
|
6
|
+
"data": {
|
|
7
|
+
"0": {
|
|
8
|
+
"json": {
|
|
9
|
+
"value": "Trigger Zone"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"name": "core::Transform",
|
|
16
|
+
"data": {
|
|
17
|
+
"0": {
|
|
18
|
+
"json": {
|
|
19
|
+
"scale": { "x": 4, "y": 3, "z": 4 }
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "core::TriggerArea",
|
|
26
|
+
"data": {
|
|
27
|
+
"0": {
|
|
28
|
+
"json": {
|
|
29
|
+
"mesh": 0,
|
|
30
|
+
"collisionMask": 8
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "asset-packs::Script",
|
|
37
|
+
"data": {
|
|
38
|
+
"0": {
|
|
39
|
+
"json": {
|
|
40
|
+
"value": [
|
|
41
|
+
{
|
|
42
|
+
"path": "{assetPath}/scripts/trigger-zone.ts",
|
|
43
|
+
"priority": 0,
|
|
44
|
+
"layout": "{\"params\":{},\"actions\":[]}"
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "f1794ec8-ed62-42c8-a71b-6c52e04b161a",
|
|
3
|
+
"name": "Trigger Area",
|
|
4
|
+
"slug": "trigger_zone",
|
|
5
|
+
"description": "An invisible area that knows who is standing in it. Name it, scale it with the gizmo, then have a script react to that name.",
|
|
6
|
+
"category": "custom",
|
|
7
|
+
"tags": [
|
|
8
|
+
"trigger",
|
|
9
|
+
"area",
|
|
10
|
+
"interactivity"
|
|
11
|
+
],
|
|
12
|
+
"drivenBy": {
|
|
13
|
+
"rule": "The area only publishes who is standing in it — a Script reacts to its name through './runtime/zoneBus', on this item or on any other entity in the scene.",
|
|
14
|
+
"code": "onZone('Front Door', 'enter', (event) => { /* what happens */ })",
|
|
15
|
+
"next": "Use the Add a reaction button below and the new Script arrives already listening to this area."
|
|
16
|
+
},
|
|
17
|
+
"version": "1.1.0",
|
|
18
|
+
"changelog": [
|
|
19
|
+
{
|
|
20
|
+
"version": "1.0.0",
|
|
21
|
+
"notes": "Initial release: an invisible named area that publishes who is standing in it, so a Script anywhere in the scene reacts to it by name with nothing wired."
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"version": "1.1.0",
|
|
25
|
+
"notes": "The placed area's Script card now shows the onZone line a Script reacts with, under its area settings."
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"origin": {
|
|
29
|
+
"source": "builtin"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// An invisible named area that knows who is standing in it. The zone's id is the
|
|
2
|
+
// entity's NAME — the one handle the creator, the script and the AI already
|
|
3
|
+
// share — so another script reacts with `isInZone('Front Hall')` and nothing has
|
|
4
|
+
// to be wired. Matching is case- and whitespace-insensitive (zoneRegistry).
|
|
5
|
+
//
|
|
6
|
+
// The area's size and rotation come from the entity's own Transform: scale is
|
|
7
|
+
// metres, so the scale gizmo is the resize tool. Detection is client-side only —
|
|
8
|
+
// the server has no avatar colliders, so a zone never fires there.
|
|
9
|
+
import { TriggerArea, triggerAreaEventsSystem, type Entity } from '@dcl/sdk/ecs'
|
|
10
|
+
import { Membership } from '~runtime/pure/membership'
|
|
11
|
+
import { emitZone, publishZone, zoneOf } from '~runtime/zoneBus'
|
|
12
|
+
|
|
13
|
+
// Collision layers by value, not by name: the SDK renamed CL_RESERVED2 to
|
|
14
|
+
// CL_MAIN_PLAYER, and this script compiles against whatever pin the creator's
|
|
15
|
+
// project happens to carry.
|
|
16
|
+
const CL_PLAYER = 4
|
|
17
|
+
const CL_MAIN_PLAYER = 8
|
|
18
|
+
const SPHERE_MESH = 1
|
|
19
|
+
|
|
20
|
+
// TriggerAreaResult carries plain numbers; Entity is the branded form of the
|
|
21
|
+
// same id. 0 is the root, never an avatar.
|
|
22
|
+
function toEntity(raw?: number): Entity | undefined {
|
|
23
|
+
return raw === undefined || raw === 0 ? undefined : (raw as Entity)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class TriggerZone {
|
|
27
|
+
private members = new Membership<Entity>()
|
|
28
|
+
private zone = ''
|
|
29
|
+
|
|
30
|
+
constructor(
|
|
31
|
+
public src: string,
|
|
32
|
+
public entity: Entity,
|
|
33
|
+
/**
|
|
34
|
+
* Whose client reacts. "this player" is right for anything that happens to
|
|
35
|
+
* the person who walked in; "any player" also fires for other avatars.
|
|
36
|
+
*/
|
|
37
|
+
public who: 'this player' | 'any player' = 'this player',
|
|
38
|
+
/** How often an entry may fire */
|
|
39
|
+
public fireWhen: 'every time' | 'once per player' | 'once ever' = 'every time',
|
|
40
|
+
/**
|
|
41
|
+
* Seconds a player may step back out before the zone counts them as gone.
|
|
42
|
+
* Deliberately NOT called a cooldown: this is boundary hysteresis, nothing to
|
|
43
|
+
* do with how often a reaction may fire — a reaction owns its own rate limit.
|
|
44
|
+
*/
|
|
45
|
+
public exitDelay: number = 0.3
|
|
46
|
+
) {}
|
|
47
|
+
|
|
48
|
+
start(): void {
|
|
49
|
+
// The local avatar's collider is CL_PLAYER|CL_MAIN_PLAYER and every remote
|
|
50
|
+
// avatar's is CL_PLAYER alone, so masking on 8 settles "this player only" in
|
|
51
|
+
// rapier — cheaper and safer than a JS identity guard.
|
|
52
|
+
const mask = this.who === 'this player' ? CL_MAIN_PLAYER : CL_PLAYER
|
|
53
|
+
if (TriggerArea.getOrNull(this.entity)?.mesh === SPHERE_MESH) {
|
|
54
|
+
TriggerArea.setSphere(this.entity, mask)
|
|
55
|
+
} else {
|
|
56
|
+
TriggerArea.setBox(this.entity, mask)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this.zone = zoneOf(this.entity)
|
|
60
|
+
publishZone(this.zone, this.entity, () => this.members.list())
|
|
61
|
+
|
|
62
|
+
// triggerAreaEventsSystem keeps exactly ONE callback per (entity, event):
|
|
63
|
+
// anything else subscribing to this entity silently replaces the zone's own
|
|
64
|
+
// detector. Consumers use the bus, never onTriggerEnter.
|
|
65
|
+
triggerAreaEventsSystem.onTriggerEnter(this.entity, (result) => this.seen(result.trigger?.entity))
|
|
66
|
+
triggerAreaEventsSystem.onTriggerStay(this.entity, (result) => this.seen(result.trigger?.entity))
|
|
67
|
+
triggerAreaEventsSystem.onTriggerExit(this.entity, (result) => this.gone(result.trigger?.entity))
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
update(dt: number): void {
|
|
71
|
+
for (const who of this.members.tick(dt, this.exitDelay)) {
|
|
72
|
+
emitZone(this.zone, 'exit', who, this.entity)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// result.trigger.entity is the avatar that moved; result.triggeredEntity is
|
|
77
|
+
// this area. Reading the wrong one is a silent no-op.
|
|
78
|
+
private seen(raw?: number): void {
|
|
79
|
+
const who = toEntity(raw)
|
|
80
|
+
if (who === undefined) return
|
|
81
|
+
if (this.members.touch(who, this.fireWhen)) emitZone(this.zone, 'enter', who, this.entity)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private gone(raw?: number): void {
|
|
85
|
+
const who = toEntity(raw)
|
|
86
|
+
if (who === undefined) return
|
|
87
|
+
this.members.drop(who)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"components": [
|
|
4
|
+
{
|
|
5
|
+
"name": "core::GltfContainer",
|
|
6
|
+
"data": {
|
|
7
|
+
"0": {
|
|
8
|
+
"json": {
|
|
9
|
+
"src": "{assetPath}/video_player.glb",
|
|
10
|
+
"visibleMeshesCollisionMask": 0,
|
|
11
|
+
"invisibleMeshesCollisionMask": 3
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "core-schema::Name",
|
|
18
|
+
"data": {
|
|
19
|
+
"0": {
|
|
20
|
+
"json": {
|
|
21
|
+
"value": "Video Screen"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "core::VideoPlayer",
|
|
28
|
+
"data": {
|
|
29
|
+
"0": {
|
|
30
|
+
"json": {
|
|
31
|
+
"src": "https://player.vimeo.com/external/552481870.m3u8?s=c312c8533f97e808fccc92b0510b085c8122a875",
|
|
32
|
+
"playing": true,
|
|
33
|
+
"volume": 1,
|
|
34
|
+
"loop": true
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "core::GltfNodeModifiers",
|
|
41
|
+
"data": {
|
|
42
|
+
"0": {
|
|
43
|
+
"json": {
|
|
44
|
+
"modifiers": [
|
|
45
|
+
{
|
|
46
|
+
"path": "",
|
|
47
|
+
"castShadows": true,
|
|
48
|
+
"material": {
|
|
49
|
+
"material": {
|
|
50
|
+
"$case": "unlit",
|
|
51
|
+
"unlit": {
|
|
52
|
+
"texture": {
|
|
53
|
+
"tex": {
|
|
54
|
+
"$case": "videoTexture",
|
|
55
|
+
"videoTexture": {
|
|
56
|
+
"videoPlayerEntity": "{self}",
|
|
57
|
+
"wrapMode": 0,
|
|
58
|
+
"filterMode": 0
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"alphaTest": 0.5,
|
|
63
|
+
"castShadows": true,
|
|
64
|
+
"alphaTexture": {
|
|
65
|
+
"tex": {
|
|
66
|
+
"$case": "texture",
|
|
67
|
+
"texture": {
|
|
68
|
+
"src": "",
|
|
69
|
+
"wrapMode": 0,
|
|
70
|
+
"filterMode": 0,
|
|
71
|
+
"offset": { "x": 0, "y": 0 },
|
|
72
|
+
"tiling": { "x": 1, "y": 1 }
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name": "asset-packs::VideoScreen",
|
|
87
|
+
"data": {
|
|
88
|
+
"0": {
|
|
89
|
+
"json": {
|
|
90
|
+
"thumbnail": "",
|
|
91
|
+
"defaultMediaSource": 0,
|
|
92
|
+
"defaultURL": "https://player.vimeo.com/external/552481870.m3u8?s=c312c8533f97e808fccc92b0510b085c8122a875"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "37188734-4562-4f21-afeb-2752c39278f4",
|
|
3
|
+
"name": "Video Screen",
|
|
4
|
+
"description": "A flat screen that plays a video file or a live stream, with volume and playback controls.",
|
|
5
|
+
"category": "custom",
|
|
6
|
+
"tags": [
|
|
7
|
+
"video",
|
|
8
|
+
"screen",
|
|
9
|
+
"stream"
|
|
10
|
+
],
|
|
11
|
+
"version": "1.0.0",
|
|
12
|
+
"changelog": [
|
|
13
|
+
{
|
|
14
|
+
"version": "1.0.0",
|
|
15
|
+
"notes": "Initial release"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"origin": {
|
|
19
|
+
"source": "builtin"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"components": [
|
|
4
|
+
{
|
|
5
|
+
"name": "core::GltfContainer",
|
|
6
|
+
"data": {
|
|
7
|
+
"0": {
|
|
8
|
+
"json": {
|
|
9
|
+
"src": "{assetPath}/Chair 1.glb",
|
|
10
|
+
"visibleMeshesCollisionMask": 0,
|
|
11
|
+
"invisibleMeshesCollisionMask": 3
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "core-schema::Name",
|
|
18
|
+
"data": {
|
|
19
|
+
"0": {
|
|
20
|
+
"json": {
|
|
21
|
+
"value": "Wooden Chair"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"513": {
|
|
25
|
+
"json": {
|
|
26
|
+
"value": "Sit Spot"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"name": "core::Transform",
|
|
33
|
+
"data": {
|
|
34
|
+
"513": {
|
|
35
|
+
"json": {
|
|
36
|
+
"position": {
|
|
37
|
+
"x": 0.0044,
|
|
38
|
+
"y": 0,
|
|
39
|
+
"z": 0.2835
|
|
40
|
+
},
|
|
41
|
+
"rotation": {
|
|
42
|
+
"x": 0,
|
|
43
|
+
"y": 0,
|
|
44
|
+
"z": 0,
|
|
45
|
+
"w": 1
|
|
46
|
+
},
|
|
47
|
+
"scale": {
|
|
48
|
+
"x": 1,
|
|
49
|
+
"y": 1,
|
|
50
|
+
"z": 1
|
|
51
|
+
},
|
|
52
|
+
"parent": 0
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"name": "asset-packs::Script",
|
|
59
|
+
"data": {
|
|
60
|
+
"0": {
|
|
61
|
+
"json": {
|
|
62
|
+
"value": [
|
|
63
|
+
{
|
|
64
|
+
"path": "{assetPath}/scripts/seat.ts",
|
|
65
|
+
"priority": 0,
|
|
66
|
+
"layout": "{\"params\":{},\"actions\":[]}"
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|