@hytopia.com/examples 1.0.17 → 1.0.19

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.
@@ -77,6 +77,9 @@
77
77
  function closeSkills() {
78
78
  document.querySelector('.skills-overlay').style.display = 'none';
79
79
  hytopia.lockPointer(true);
80
+
81
+ // Close any open mobile tooltips
82
+ closeAllMobileTooltips();
80
83
  }
81
84
 
82
85
  // Update Functions
@@ -107,6 +110,9 @@
107
110
  const skillItem = createSkillItem(skill);
108
111
  skillsGrid.appendChild(skillItem);
109
112
  });
113
+
114
+ // Close any open mobile tooltips after updating skills
115
+ closeAllMobileTooltips();
110
116
  }
111
117
 
112
118
  function updateSkillsExp(data) {
@@ -174,6 +180,54 @@
174
180
  // Event Listeners
175
181
  function setupEventListeners() {
176
182
  document.querySelector('.skills-close').addEventListener('click', closeSkills);
183
+
184
+ // Setup mobile tooltip handling
185
+ setupMobileTooltips();
186
+ }
187
+
188
+ // Mobile tooltip handling
189
+ function setupMobileTooltips() {
190
+ // Check if we're on mobile
191
+ const isMobile = document.body.classList.contains('mobile');
192
+ if (!isMobile) return;
193
+
194
+ // Add click handler to skills container for event delegation
195
+ document.querySelector('.skills-skills-grid').addEventListener('click', handleMobileTooltipClick);
196
+
197
+ // Add click handler to document to close tooltips when clicking outside
198
+ document.addEventListener('click', handleDocumentClick);
199
+ }
200
+
201
+ function handleMobileTooltipClick(e) {
202
+ const skillItem = e.target.closest('.skills-skill-item');
203
+ if (!skillItem) return;
204
+
205
+ e.stopPropagation();
206
+
207
+ const tooltip = skillItem.querySelector('.skills-skill-tooltip');
208
+ if (!tooltip) return;
209
+
210
+ // Close any other open tooltips
211
+ closeAllMobileTooltips();
212
+
213
+ // Toggle this tooltip
214
+ tooltip.classList.add('skills-mobile-tooltip-visible');
215
+ }
216
+
217
+ function handleDocumentClick(e) {
218
+ // Close tooltips when clicking outside
219
+ if (!e.target.closest('.skills-skill-item')) {
220
+ closeAllMobileTooltips();
221
+ }
222
+ }
223
+
224
+ function closeAllMobileTooltips() {
225
+ const visibleTooltips = document.querySelectorAll('.skills-mobile-tooltip-visible');
226
+ if (visibleTooltips.length > 0) {
227
+ visibleTooltips.forEach(tooltip => {
228
+ tooltip.classList.remove('skills-mobile-tooltip-visible');
229
+ });
230
+ }
177
231
  }
178
232
 
179
233
  // Initialize
@@ -490,96 +544,135 @@
490
544
  /* Mobile Styles */
491
545
  body.mobile .skills-container {
492
546
  width: auto;
493
- max-width: 98vw;
494
- min-width: 300px;
547
+ max-width: 680px;
548
+ min-width: 475px;
549
+ border-radius: 8px;
495
550
  }
496
551
 
497
552
  body.mobile .skills-header {
498
- padding: 6px 8px;
553
+ padding: 8px 12px;
554
+ border-radius: 8px 8px 0 0;
499
555
  }
500
556
 
501
557
  body.mobile .skills-title {
502
- font-size: 11px;
558
+ font-size: 14px;
503
559
  }
504
560
 
505
561
  body.mobile .skills-close {
506
- width: 18px;
507
- height: 18px;
508
- font-size: 12px;
562
+ width: 24px;
563
+ height: 24px;
564
+ font-size: 16px;
565
+ border-radius: 6px;
509
566
  }
510
567
 
511
568
  body.mobile .skills-content {
512
- padding: 6px;
569
+ padding: 12px;
513
570
  }
514
571
 
515
572
  body.mobile .skills-player-section,
516
573
  body.mobile .skills-skills-section {
517
- margin-bottom: 8px;
518
- padding: 6px;
574
+ padding: 10px;
575
+ border-radius: 6px;
519
576
  }
520
577
 
521
578
  body.mobile .skills-section-title {
522
- font-size: 10px;
523
- margin-bottom: 6px;
579
+ font-size: 12px;
580
+ margin-bottom: 8px;
524
581
  }
525
582
 
526
583
  body.mobile .skills-level-display {
527
- margin-bottom: 4px;
584
+ margin-bottom: 8px;
528
585
  }
529
586
 
530
587
  body.mobile .skills-level-number {
531
- font-size: 12px;
588
+ font-size: 16px;
532
589
  }
533
590
 
534
591
  body.mobile .skills-exp-bar {
535
- height: 14px;
592
+ height: 16px;
593
+ border-radius: 6px;
536
594
  }
537
595
 
538
596
  body.mobile .skills-exp-text {
539
- font-size: 8px;
597
+ font-size: 10px;
540
598
  }
541
599
 
542
600
  body.mobile .skills-skills-grid {
543
- grid-template-columns: 1fr 1fr;
544
- gap: 4px;
601
+ grid-template-columns: 1fr 1fr 1fr;
602
+ gap: 6px;
545
603
  }
546
604
 
547
605
  body.mobile .skills-skill-item {
548
- gap: 8px;
549
- padding: 3px;
606
+ gap: 6px;
607
+ padding: 4px 8px;
608
+ border-radius: 6px;
609
+ min-height: 40px;
610
+ cursor: pointer;
611
+ -webkit-tap-highlight-color: rgba(255, 255, 255, 0.1);
550
612
  }
551
613
 
552
614
  body.mobile .skills-skill-icon {
553
615
  width: 28px;
554
616
  height: 28px;
555
- }
556
-
557
- body.mobile .skills-skill-icon-img {
558
- width: 100%;
559
- height: 100%;
617
+ border-radius: 6px;
560
618
  }
561
619
 
562
620
  body.mobile .skills-skill-header {
563
- margin-bottom: 3px;
621
+ margin-bottom: 4px;
564
622
  }
565
623
 
566
624
  body.mobile .skills-skill-name {
567
- font-size: 9px;
625
+ font-size: 10px;
626
+ overflow: hidden;
627
+ text-overflow: ellipsis;
628
+ white-space: nowrap;
568
629
  }
569
630
 
570
631
  body.mobile .skills-skill-level {
571
- font-size: 8px;
632
+ font-size: 9px;
633
+ flex-shrink: 0;
572
634
  }
573
635
 
574
636
  body.mobile .skills-skill-exp-bar {
575
637
  height: 10px;
638
+ border-radius: 6px;
576
639
  }
577
640
 
578
641
  body.mobile .skills-skill-exp-text {
579
- font-size: 6px;
642
+ font-size: 7px;
580
643
  }
581
644
 
582
645
  body.mobile .skills-skill-tooltip {
583
- display: none;
646
+ opacity: 0;
647
+ visibility: hidden;
648
+ transform: translateY(-4px);
649
+ transition: all 0.2s ease;
650
+ }
651
+
652
+ body.mobile .skills-mobile-tooltip-visible {
653
+ opacity: 1 !important;
654
+ visibility: visible !important;
655
+ transform: translateY(-8px) !important;
656
+ }
657
+
658
+ body.mobile .skills-skill-tooltip-content {
659
+ max-width: 180px;
660
+ font-size: 10px;
661
+ }
662
+
663
+ /* Center the caret on mobile */
664
+ body.mobile .skills-skill-tooltip-content::after {
665
+ left: 50% !important;
666
+ transform: translateX(-50%) !important;
667
+ }
668
+
669
+ body.mobile .skills-skill-tooltip-content::before {
670
+ left: 50% !important;
671
+ transform: translateX(-50%) !important;
672
+ }
673
+
674
+ /* Enable scrolling if needed */
675
+ body.mobile .skills-content * {
676
+ touch-action: pan-y !important;
584
677
  }
585
678
  </style>
@@ -123,12 +123,75 @@ window.ItemTooltips = (function() {
123
123
  if (existingTooltip) existingTooltip.remove();
124
124
  }
125
125
 
126
+ // Mobile tooltip handling
127
+ let mobileTooltipActive = false;
128
+
129
+ function initializeMobileTooltips() {
130
+ // Check if we're on mobile
131
+ const isMobile = document.body.classList.contains('mobile');
132
+ if (!isMobile) return;
133
+
134
+ // Add click handler to document for event delegation
135
+ document.addEventListener('click', handleMobileTooltipClick, true);
136
+ }
137
+
138
+ function handleMobileTooltipClick(e) {
139
+ // List of tooltip container selectors - include quest reward enabled class
140
+ const tooltipContainers = [
141
+ '.backpack-slot', '.backpack-hotbar-slot', '.backpack-wearable-slot',
142
+ '.hud-hotbar-slot', '.merchant-slot', '.merchant-hotbar-slot',
143
+ '.crafting-slot', '.crafting-requirement-item',
144
+ '.quests-reward-item', '.quests-reward-item-tooltip-enabled'
145
+ ];
146
+
147
+ // Check if click is on a tooltip container
148
+ const container = e.target.closest(tooltipContainers.join(', '));
149
+
150
+ if (container) {
151
+ // Find tooltip in this container
152
+ const tooltip = container.querySelector([
153
+ '.item-tooltip', '.backpack-item-tooltip', '.merchant-item-tooltip',
154
+ '.crafting-item-tooltip', '.crafting-requirement-tooltip', '.quests-reward-item-tooltip'
155
+ ].join(', '));
156
+
157
+ if (tooltip) {
158
+ // Close any other open tooltips
159
+ closeAllMobileTooltips();
160
+
161
+ // Show this tooltip
162
+ tooltip.classList.add('mobile-tooltip-visible');
163
+ mobileTooltipActive = true;
164
+ }
165
+ } else {
166
+ // Click outside any container - close all tooltips
167
+ closeAllMobileTooltips();
168
+ }
169
+ }
170
+
171
+ function closeAllMobileTooltips() {
172
+ const visibleTooltips = document.querySelectorAll('.mobile-tooltip-visible');
173
+ if (visibleTooltips.length > 0) {
174
+ visibleTooltips.forEach(tooltip => {
175
+ tooltip.classList.remove('mobile-tooltip-visible');
176
+ });
177
+ mobileTooltipActive = false;
178
+ }
179
+ }
180
+
181
+ // Initialize mobile tooltips when DOM is ready
182
+ if (document.readyState === 'loading') {
183
+ document.addEventListener('DOMContentLoaded', initializeMobileTooltips);
184
+ } else {
185
+ initializeMobileTooltips();
186
+ }
187
+
126
188
  // Public API
127
189
  return {
128
190
  parseText: parseText,
129
191
  hasTooltipData: hasTooltipData,
130
192
  createTooltip: createTooltip,
131
- removeTooltip: removeTooltip
193
+ removeTooltip: removeTooltip,
194
+ closeAllMobileTooltips: closeAllMobileTooltips
132
195
  };
133
196
  })();
134
197
  </script>
@@ -156,8 +219,7 @@ window.ItemTooltips = (function() {
156
219
  .merchant-hotbar-slot:hover .item-tooltip,
157
220
  .crafting-slot:hover .item-tooltip,
158
221
  .crafting-requirement-item:hover .item-tooltip,
159
- .quests-reward-item:hover .item-tooltip,
160
- /* Tooltip visibility on hover - Specific classes */
222
+
161
223
  .backpack-slot:hover .backpack-item-tooltip,
162
224
  .backpack-hotbar-slot:hover .backpack-item-tooltip,
163
225
  .backpack-wearable-slot:hover .backpack-item-tooltip,
@@ -281,14 +343,72 @@ window.ItemTooltips = (function() {
281
343
  font-size: 11px;
282
344
  }
283
345
 
284
- /* Mobile - Hide tooltips on mobile devices */
346
+ /* Mobile - Control tooltip visibility on mobile devices */
285
347
  body.mobile .item-tooltip,
286
348
  body.mobile .backpack-item-tooltip,
287
349
  body.mobile .merchant-item-tooltip,
288
350
  body.mobile .crafting-item-tooltip,
289
351
  body.mobile .crafting-requirement-tooltip,
290
352
  body.mobile .quests-reward-item-tooltip {
291
- display: none;
353
+ opacity: 0;
354
+ visibility: hidden;
355
+ transform: translateY(-4px);
356
+ transition: all 0.2s ease;
357
+ }
358
+
359
+ /* Mobile tooltip visibility when tapped */
360
+ body.mobile .mobile-tooltip-visible {
361
+ opacity: 1 !important;
362
+ visibility: visible !important;
363
+ transform: translateY(-8px) !important;
364
+ }
365
+
366
+ /* Improve mobile tooltip positioning and touch targets */
367
+ body.mobile .backpack-slot,
368
+ body.mobile .backpack-hotbar-slot,
369
+ body.mobile .backpack-wearable-slot,
370
+ body.mobile .hud-hotbar-slot,
371
+ body.mobile .merchant-slot,
372
+ body.mobile .merchant-hotbar-slot,
373
+ body.mobile .crafting-slot,
374
+ body.mobile .crafting-requirement-item,
375
+ body.mobile .quests-reward-item,
376
+ body.mobile .quests-reward-item-tooltip-enabled {
377
+ cursor: pointer;
378
+ -webkit-tap-highlight-color: rgba(255, 255, 255, 0.1);
379
+ }
380
+
381
+ /* Center carets on mobile tooltips */
382
+ body.mobile .item-tooltip-content::after,
383
+ body.mobile .backpack-item-tooltip-content::after,
384
+ body.mobile .merchant-item-tooltip-content::after,
385
+ body.mobile .crafting-item-tooltip-content::after,
386
+ body.mobile .crafting-requirement-tooltip-content::after,
387
+ body.mobile .quests-reward-item-tooltip-content::after {
388
+ left: 50% !important;
389
+ transform: translateX(-50%) !important;
390
+ }
391
+
392
+ body.mobile .item-tooltip-content::before,
393
+ body.mobile .backpack-item-tooltip-content::before,
394
+ body.mobile .merchant-item-tooltip-content::before,
395
+ body.mobile .crafting-item-tooltip-content::before,
396
+ body.mobile .crafting-requirement-tooltip-content::before,
397
+ body.mobile .quests-reward-item-tooltip-content::before {
398
+ left: 50% !important;
399
+ transform: translateX(-50%) !important;
400
+ }
401
+
402
+ /* Mobile tooltip content sizing */
403
+ body.mobile .item-tooltip-content,
404
+ body.mobile .backpack-item-tooltip-content,
405
+ body.mobile .merchant-item-tooltip-content,
406
+ body.mobile .crafting-item-tooltip-content,
407
+ body.mobile .crafting-requirement-tooltip-content,
408
+ body.mobile .quests-reward-item-tooltip-content {
409
+ max-width: 220px;
410
+ font-size: 11px;
411
+ padding: 8px 10px;
292
412
  }
293
413
 
294
414
  /* Mouse Follower Tooltip (for backpack drag system) */
@@ -77,7 +77,7 @@ export default class GameManager {
77
77
  }
78
78
 
79
79
  private _selectWorldForPlayer = async (player: Player): Promise<World | undefined> => {
80
- const gamePlayer = await GamePlayer.getOrCreate(player);
80
+ const gamePlayer = GamePlayer.getOrCreate(player);
81
81
  return gamePlayer.currentRegion?.world ?? this._startRegion.world;
82
82
  }
83
83
  }
@@ -88,13 +88,15 @@ export default class GamePlayer {
88
88
  this.hotbar.onSelectedItemChanged = this._onHotbarSelectedItemChanged;
89
89
  }
90
90
 
91
- public static async getOrCreate(player: Player): Promise<GamePlayer> {
91
+ public static getOrCreate(player: Player): GamePlayer {
92
92
  let gamePlayer = this._instances.get(player.id);
93
+
93
94
  if (!gamePlayer) {
94
95
  gamePlayer = new GamePlayer(player);
95
- await gamePlayer.load();
96
+ gamePlayer.load();
96
97
  this._instances.set(player.id, gamePlayer);
97
98
  }
99
+
98
100
  return gamePlayer;
99
101
  }
100
102
 
@@ -342,8 +344,8 @@ export default class GamePlayer {
342
344
  this.player.joinWorld(region.world);
343
345
  }
344
346
 
345
- public async load(): Promise<void> {
346
- const serializedGamePlayerData = await this.player.getPersistedData();
347
+ public load(): void {
348
+ const serializedGamePlayerData = this.player.getPersistedData();
347
349
 
348
350
  if (serializedGamePlayerData) { // Existing player, load their state
349
351
  this._loadFromSerializedData(serializedGamePlayerData as SerializedGamePlayerData);
@@ -140,9 +140,8 @@ export default class GameRegion {
140
140
  }
141
141
  }
142
142
 
143
- protected async onPlayerJoin(player: Player) {
144
- console.log('onPlayerJoin', this.name);
145
- const gamePlayer = await GamePlayer.getOrCreate(player);
143
+ protected onPlayerJoin(player: Player) {
144
+ const gamePlayer = GamePlayer.getOrCreate(player);
146
145
 
147
146
  // Set the current region for the player
148
147
  gamePlayer.setCurrentRegion(this);
@@ -153,11 +152,6 @@ export default class GameRegion {
153
152
  const gamePlayerEntity = new GamePlayerEntity(gamePlayer);
154
153
 
155
154
  gamePlayerEntity.spawn(this._world, spawnPoint, Quaternion.fromEuler(0, spawnFacingAngle, 0));
156
-
157
- // Since we're using an async onPlayerJoin, we need to explicitly set the camera
158
- // since the camera attachment logic as of SDK 0.6.7 only checks for an entity
159
- // the first tick after a player joins a world in order to auto attach the camera.
160
- player.camera.setAttachedToEntity(gamePlayerEntity);
161
155
 
162
156
  // Make the camera look at the correct spawn facing angle.
163
157
  // Calculate look direction based on facing angle (identity direction is -z, consistent with threejs)
@@ -200,8 +194,8 @@ export default class GameRegion {
200
194
  // The HYTOPIA SDK handles resynchronization of all persisted state back to the player client such as
201
195
  // their entity, scene ui states, etc, but anything that uses ephemeral state (Such as UI) we need
202
196
  // to handle reloading for them manually here.
203
- protected async onPlayerReconnected(player: Player) {
204
- const gamePlayer = await GamePlayer.getOrCreate(player);
197
+ protected onPlayerReconnected(player: Player) {
198
+ const gamePlayer = GamePlayer.getOrCreate(player);
205
199
  gamePlayer.onPlayerReconnected();
206
200
  }
207
201
  }
@@ -15,7 +15,7 @@ import {
15
15
 
16
16
  const MOVEMENT_NOT_STUCK_DISTANCE_SQUARED = 3;
17
17
  const COMBAT_REGEN_DEFAULT_DELAY_MS = 7000; // 7 seconds
18
- const COMBAT_REGEN_DEFAULT_RATE = 0.03; // 3% per second
18
+ const COMBAT_REGEN_DEFAULT_RATE = 0.05; // 5% per interval
19
19
  const COMBAT_REGEN_INTERVAL_MS = 3000; // 3 seconds
20
20
 
21
21
  import BaseEntity, { BaseEntityOptions } from './BaseEntity';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hytopia.com/examples",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
4
4
  "description": "",
5
5
  "license": "ISC",
6
6
  "author": "",
@@ -1,103 +0,0 @@
1
- {
2
- "health": 120,
3
- "currentRegionId": "chitter-forest",
4
- "skillExperience": [
5
- [
6
- "exploration",
7
- 225
8
- ],
9
- [
10
- "combat",
11
- 162
12
- ],
13
- [
14
- "agility",
15
- 20
16
- ]
17
- ],
18
- "backpack": {
19
- "items": []
20
- },
21
- "hotbar": {
22
- "items": [
23
- {
24
- "position": 0,
25
- "itemId": "dull_sword"
26
- },
27
- {
28
- "position": 2,
29
- "itemId": "toy_sword"
30
- },
31
- {
32
- "position": 3,
33
- "itemId": "gold",
34
- "quantity": 82
35
- },
36
- {
37
- "position": 1,
38
- "itemId": "ratkin_tail"
39
- },
40
- {
41
- "position": 4,
42
- "itemId": "ratkin_tooth"
43
- },
44
- {
45
- "position": 5,
46
- "itemId": "ratkin_eyes",
47
- "quantity": 3
48
- },
49
- {
50
- "position": 6,
51
- "itemId": "ratkin_bones",
52
- "quantity": 3
53
- }
54
- ]
55
- },
56
- "questLog": {
57
- "quests": [
58
- {
59
- "questId": "welcome-to-stalkhaven",
60
- "state": "completed",
61
- "objectiveProgress": {
62
- "talk-to-mark": 1
63
- }
64
- },
65
- {
66
- "questId": "exploring-stalkhaven",
67
- "state": "completed",
68
- "objectiveProgress": {
69
- "talk-to-mycelis": 1,
70
- "talk-to-finn": 1,
71
- "talk-to-sporn": 1,
72
- "talk-to-mark": 1
73
- }
74
- },
75
- {
76
- "questId": "tested-mettle",
77
- "state": "active",
78
- "objectiveProgress": {
79
- "kill-5-ratkin": 5,
80
- "dodge-3-times": 3,
81
- "talk-to-mark": 0
82
- }
83
- }
84
- ]
85
- },
86
- "storage": {
87
- "items": []
88
- },
89
- "wearables": {
90
- "items": [
91
- {
92
- "position": 1,
93
- "itemId": "adventurer_tunic"
94
- }
95
- ]
96
- },
97
- "currentRegionSpawnFacingAngle": 0,
98
- "currentRegionSpawnPoint": {
99
- "x": -7,
100
- "y": 2,
101
- "z": 76
102
- }
103
- }