@ericchen1990/pano-view 4.1.0 → 5.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/README.md CHANGED
@@ -1692,10 +1692,28 @@ via `label`. When collapsible, `defaultExpanded` defaults to `true`.
1692
1692
 
1693
1693
  ### Appearance and CSS hooks
1694
1694
 
1695
- Pass `appearance` for common chrome tokens without writing CSS. The active-item
1696
- ring sits above the thumbnail and is controlled by `selectionColor` /
1697
- `selectionWidth` (`selectionWidth: 0` hides it). Scene titles default to start
1698
- alignment; set `labelAlign: "center"` or `"end"` to change that.
1695
+ Pass `appearance` for common chrome tokens without writing CSS. The border sits
1696
+ inside the thumbnail: `selectionColor` defaults to white for the current scene;
1697
+ `focusColor` defaults to `"#7dd3fc"` for mouse hover and keyboard focus, taking
1698
+ priority over selection. All three states share `selectionWidth` (default 2px).
1699
+ `selectionWidth: 0` hides these borders while retaining the independent keyboard
1700
+ focus outline. Scene titles default to start alignment; set `labelAlign: "center"`
1701
+ or `"end"` to change that.
1702
+
1703
+ Set `showVisited` (default `false`) to show a dark circular check icon in the
1704
+ thumbnail's top-right corner, with no visible text. `visitedLabel` (default
1705
+ `"Visited"`) customizes only the accessible description. A scene is recorded when
1706
+ `Scenes` / `ProjectScenes` first reports it paintable, including the initial and
1707
+ current scene; clicks, preloads and failed loads do not count. Both menu types in
1708
+ the same `PanoViewer` share this session history, including visits made before
1709
+ turning the option on. Collapsing, hiding or remounting a menu and entering/exiting
1710
+ VR retain the history. Refreshing or remounting the viewer clears it. Standalone
1711
+ menus without a scene-ready source do not generate visits; `activeId` alone does
1712
+ not record one.
1713
+
1714
+ ```tsx
1715
+ <PanoSceneMenu items={menuItems} activeId={activeSceneId} onSelect={setActiveSceneId} showVisited />
1716
+ ```
1699
1717
 
1700
1718
  ```tsx
1701
1719
  <PanoSceneMenu
@@ -1732,7 +1750,8 @@ use `className` / `style` against these stable classes:
1732
1750
 
1733
1751
  The root also exposes `data-placement`, `data-align`, `data-orientation`
1734
1752
  (`horizontal` | `vertical`), `data-expanded`, and `data-collapsible`. The active
1735
- item has `data-active="true"`.
1753
+ item has `data-active="true"`; a visited item has `data-visited="true"` when
1754
+ `showVisited` is enabled. The badge uses `pano-scene-menu-visited`.
1736
1755
 
1737
1756
  When `collapsible` is set, `toggle` replaces the edge-tab icon or restyles that
1738
1757
  button. Omit `toggle` to keep the default chevron. Pass an element (`<Icon />`)
@@ -2796,11 +2815,10 @@ handler, `onEnded`, or playback error.
2796
2815
  ## VideoHotspot
2797
2816
 
2798
2817
  `VideoHotspot` uses an `HTMLVideoElement` and `VideoTexture`. Its `playing`
2799
- prop is likewise controlled: toggle it from your click handler or application
2800
- state. On source change or unmount, the element is paused and its texture is
2818
+ prop is likewise controlled: initialize it to `false` for manual playback, then toggle it from your click handler or application state. On source change or unmount, the element is paused and its texture is
2801
2819
  released. `playsInline` defaults to `true` and uses the same inline-playback
2802
2820
  attributes as `PanoVideo`. The element is mounted inside the viewer, hidden,
2803
- so mobile browsers keep it in the page. `muted` defaults to `true`, `loop` to
2821
+ so mobile browsers keep it in the page. `muted` defaults to `false`, `loop` to
2804
2822
  `false`, `preload` to `"metadata"` (also `"none"` | `"auto"`), and `volume` to
2805
2823
  `1` (0–1). Omitted size defaults to `16×9`. Cross-origin media may set
2806
2824
  `crossOrigin` (`""` | `"anonymous"` | `"use-credentials"`).
@@ -2818,7 +2836,6 @@ import { VideoHotspot } from "@ericchen1990/pano-view";
2818
2836
  src="/hotspots/room.webm"
2819
2837
  poster="/hotspots/room-poster.webp"
2820
2838
  playing={isClipPlaying}
2821
- muted
2822
2839
  volume={0.8}
2823
2840
  onClick={() => setClipPlaying((playing) => !playing)}
2824
2841
  onEnded={() => setClipPlaying(false)}
@@ -2827,7 +2844,7 @@ import { VideoHotspot } from "@ericchen1990/pano-view";
2827
2844
  />;
2828
2845
  ```
2829
2846
 
2830
- Browsers can reject unmuted or otherwise non-gesture playback. In that case
2847
+ Loading or entering VR does not start playback. Readiness events and seeking preserve controller-set mute and volume; changing the corresponding props or source applies the new settings. Pass `muted` explicitly when you want silent playback. Browsers can reject unmuted or otherwise non-gesture playback. In that case
2831
2848
  `onPlaybackStateChange` receives `"blocked"` and `onPlaybackError` receives
2832
2849
  the browser error; retain control of `playing` in the host and offer an
2833
2850
  explicit user action.
@@ -3191,3 +3208,52 @@ Hover runs once per logical hotspot boundary, skips touch and keyboard focus, an
3191
3208
  ## VR control groups
3192
3209
 
3193
3210
  Customizable VR-only icon groups support media, models and scrolling. See the [VR controls guide](./docs/dialogs.md#vr-icon-controls-and-scrolling) for APIs and examples.
3211
+
3212
+ ## WebVRSceneMenu
3213
+
3214
+ Mount beside `WebVR` and `Scenes` inside `PanoViewer`. This native spatial menu appears in WebXR, MobileVR and desktop simulated VR. Previous/next buttons surround a circular scene-menu button below the horizon. Opening it reveals a curved thumbnail grid with pagination, gaze/pointer controls and accessible keyboard buttons. The active scene has a border and check mark; reopening locates its page.
3215
+
3216
+ ```tsx
3217
+ <WebVRSceneMenu
3218
+ items={[
3219
+ { id: "hall", thumbnailUrl: "/hall.webp", title: "Hall" },
3220
+ { id: "garden", thumbnailUrl: "/garden.webp", title: "Garden" },
3221
+ ]}
3222
+ activeId={activeSceneId}
3223
+ onSelect={setActiveSceneId}
3224
+ columns={4}
3225
+ rows={3}
3226
+ appearance={{ labelPlacement: "center", selectionColor: "#ffffff" }}
3227
+ />
3228
+ ```
3229
+
3230
+ Items reuse `PanoSceneMenuItem`. Titles default to centered image overlays, wrap to two lines and truncate with an ellipsis. Empty titles fall back to IDs; accessible names retain the full title. Thumbnail sources must permit cross-origin image access. Cards remain selectable when images fail.
3231
+
3232
+ | Prop | Default / range |
3233
+ | --- | --- |
3234
+ | `layout` | `"compact"` (default, original curved grid), `"flat"` (flat wall), or `"arc"` (independent flat cards around the viewer) |
3235
+ | `displayMode` | `"paged"` (default) or `"all"`; all mode grows rows, ignores `rows`, and hides paging controls |
3236
+ | `arcAngle` | 180°; clamped to 60–360°, used only by arc layout |
3237
+ | `columns`, `rows` | compact/flat: 4 columns; arc: automatic (8 at 180°, 16 at 360°). Column ranges: compact 2–4, flat/arc 2–24. Paged rows: 3, range 1–3 |
3238
+ | `loop` | `true`; wraps scene navigation, never pagination |
3239
+ | `closeOnSelect` | `true`; use `false` for continuous browsing |
3240
+ | `follow` | `true`; navigation follows horizontal heading, the open grid remains anchored |
3241
+ | `navigationPitch` | −25 degrees; −40 to −15 |
3242
+ | `distance`, `scale` | 2 meters, 1; ranges 1.5–3, 0.75–1.25 |
3243
+ | `fadeDurationMs` | 200; 0–600ms, respects reduced motion |
3244
+ | `showTitles` | `true` |
3245
+ | `showVisited`, `visitedLabel` | `false`, `"Visited"`; icon-only visit badge and its accessible description |
3246
+
3247
+ Dwell timing inherits `WebVR.cursorDwellMs`. `activeId` owns selection; `onSelect` requests navigation from the host, which retains scene loading/error handling. Dialogs and VR Setup temporarily hide the menu. Empty lists render nothing; a single scene disables previous/next navigation.
3248
+
3249
+ The bounded `appearance` interface includes `controlColor` (white), `controlBackground` (`transparent`), `controlOpacity` (0.75, range 0–1), `selectionColor` (white), `focusColor` (`#7dd3fc`), `selectionWidth` (4, range 0–8), `borderRadius` (8, range 0–48), `labelColor` (white), `labelBackground` (`transparent`), `fontSize` (28, range 16–48), and `labelPlacement` (`"center"` or `"bottom"`). Scene outlines meet the thumbnail edge from the outside. Selected, gaze and keyboard-focus borders share `selectionWidth`; zero hides them while retaining a separate keyboard-focus indicator. The optional visited check icon is independent of selection and remains visible at zero border width. The current scene uses `selectionColor`; gaze and keyboard focus use `focusColor`, taking priority on the current scene. Sizes use reference-canvas pixels and follow the overall scale. Exports include `WebVRSceneMenuProps`, `WebVRSceneMenuAppearance`, and `DEFAULT_WEBVR_SCENE_MENU_APPEARANCE`.
3250
+
3251
+ `showVisited` and `visitedLabel` follow the same session and scene-ready rules as `PanoSceneMenu` above. The badge remains visible when `showTitles={false}` or a thumbnail fails to load. Dialogs, VR Setup, pagination and VR re-entry preserve the shared viewer history.
3252
+
3253
+ The `/webvr` example teaches VR entry, exit, capability events and gaze activation. `/vr-scene-menu` includes behavior, layout and appearance controls, editable scene titles, a 25-scene pagination fixture, reset, and a regular scene menu for checking shared visit history across VR entry/exit. `/spatial-controls` teaches media, model and scrolling targets; `/immersive-tour` combines them. Settings live in page state only.
3254
+
3255
+ The floating navigation is a compact button group with equal-height icons, transparent backgrounds and subtle shadows for contrast against the panorama.
3256
+
3257
+ Flat and arc layouts use bounded texture atlases. Compact/flat default to four columns; arc defaults to one column per 22.5° (8 for a semicircle, 16 for a full circle). Compact supports 2–4 columns; new layouts support 2–24. Paged rows default to 3, clamped to 1–3. All mode extends the wall without shrinking cards, so large lists require more looking around. Opening centers the menu on the current heading; it then follows translation but not head rotation. New layouts keep close/paging controls in a separate forward control strip. The `/vr-scene-menu` playground exposes layout, display mode, and arc angle; leave columns blank for automatic defaults.
3258
+
3259
+ VR scene titles default to a transparent background with a subtle dark text shadow. Menu textures use 2× raster resolution, mipmaps and anisotropic filtering while layout and hit areas remain unchanged.
package/README.zh-CN.md CHANGED
@@ -1540,7 +1540,13 @@ export function Tour() {
1540
1540
 
1541
1541
  ### 外观与样式钩子
1542
1542
 
1543
- 常用外观可用 `appearance`,不必手写 CSS。当前项边框叠在缩略图上方,可用 `selectionColor` / `selectionWidth` 调节(`selectionWidth: 0` 隐藏);场景名默认左对齐,设 `labelAlign: "center"` 或 `"end"` 可改对齐。
1543
+ 常用外观可用 `appearance`,不必手写 CSS。场景边框位于缩略图内侧:当前场景使用 `selectionColor`(默认白色),鼠标悬停和键盘焦点使用 `focusColor`(默认 `"#7dd3fc"`),交互颜色优先于选中颜色。三种状态共用 `selectionWidth`(默认 2px);设为 `0` 隐藏这些边框,但保留独立的键盘焦点提示。场景名默认左对齐,设 `labelAlign: "center"` 或 `"end"` 可改对齐。
1544
+
1545
+ 设置 `showVisited`(默认 `false`)后,已浏览场景的缩略图右上角显示深色圆底的勾选图标,不增加可见文字。`visitedLabel`(默认 `"Visited"`)只用于无障碍描述。`Scenes` / `ProjectScenes` 在场景首次可显示时记录,包括首个场景和当前场景;点击、预加载及加载失败不计入。同一 `PanoViewer` 内的普通和 VR 菜单共享本次会话记录,也包含启用开关前浏览过的场景。收起、隐藏、重新挂载菜单或进出 VR 均保留记录;刷新或重新挂载查看器后清空。独立菜单没有场景就绪来源时不会产生记录,单独改变 `activeId` 不会标记已浏览。
1546
+
1547
+ ```tsx
1548
+ <PanoSceneMenu items={menuItems} activeId={activeSceneId} onSelect={setActiveSceneId} showVisited visitedLabel="已浏览" />
1549
+ ```
1544
1550
 
1545
1551
  ```tsx
1546
1552
  <PanoSceneMenu
@@ -1573,7 +1579,7 @@ export function Tour() {
1573
1579
  - `pano-scene-menu-item` / `pano-scene-menu-thumb` / `pano-scene-menu-label`
1574
1580
  - `pano-scene-menu-control` / `pano-scene-menu-arrow` / `pano-scene-menu-toggle`
1575
1581
 
1576
- 根节点还带 `data-placement`、`data-align`、`data-orientation`(`horizontal` | `vertical`)、`data-expanded`、`data-collapsible`;当前项带 `data-active="true"`。
1582
+ 根节点还带 `data-placement`、`data-align`、`data-orientation`(`horizontal` | `vertical`)、`data-expanded`、`data-collapsible`;当前项带 `data-active="true"`。启用 `showVisited` 时,已浏览项带 `data-visited="true"`,图标类名为 `pano-scene-menu-visited`。
1577
1583
 
1578
1584
  `collapsible` 时,边缘拉手可用 `toggle` 换图标或改样式。省略 `toggle` 时仍是默认箭头。`icon` 传元素(`<Icon />`),不要传组件类型。图标要随收起状态变化时传函数,参数为 `{ collapsed }`(菜单展开时 `collapsed` 为 `false`)。`className` 追加到按钮上。`style` 覆盖背景、边框、颜色和尺寸;位置和 `transform` 由贴边布局负责,不要在 `style` 里改。默认箭头使用 `currentColor`,只改 `style.color` 就会变色。
1579
1585
 
@@ -2410,7 +2416,7 @@ import { SequenceHotspot } from "@ericchen1990/pano-view";
2410
2416
 
2411
2417
  ## VideoHotspot
2412
2418
 
2413
- `VideoHotspot` 使用 `HTMLVideoElement` 与 `VideoTexture`。其 `playing` prop 同样受控:在点击处理或应用状态中切换。源变更或卸载时元素暂停并释放纹理。`playsInline` 默认 `true`,并使用与 `PanoVideo` 相同的内联播放属性。元素会隐藏挂在查看器内,以便移动端浏览器把它留在页面中。`muted` 默认 `true`,`loop` 默认 `false`,`preload` 默认 `"metadata"`(另可 `"none"` | `"auto"`),`volume` 默认 `1`(0–1)。省略尺寸时默认 `16×9`。非同源资源可设 `crossOrigin`(`""` | `"anonymous"` | `"use-credentials"`)。
2419
+ `VideoHotspot` 使用 `HTMLVideoElement` 与 `VideoTexture`。其 `playing` prop 同样受控:手动播放时初始化为 `false`,在点击处理或应用状态中切换。源变更或卸载时元素暂停并释放纹理。`playsInline` 默认 `true`,并使用与 `PanoVideo` 相同的内联播放属性。元素会隐藏挂在查看器内,以便移动端浏览器把它留在页面中。`muted` 默认 `false`,`loop` 默认 `false`,`preload` 默认 `"metadata"`(另可 `"none"` | `"auto"`),`volume` 默认 `1`(0–1)。省略尺寸时默认 `16×9`。非同源资源可设 `crossOrigin`(`""` | `"anonymous"` | `"use-credentials"`)。
2414
2420
 
2415
2421
  ```tsx
2416
2422
  import { VideoHotspot } from "@ericchen1990/pano-view";
@@ -2425,7 +2431,6 @@ import { VideoHotspot } from "@ericchen1990/pano-view";
2425
2431
  src="/hotspots/room.webm"
2426
2432
  poster="/hotspots/room-poster.webp"
2427
2433
  playing={isClipPlaying}
2428
- muted
2429
2434
  volume={0.8}
2430
2435
  onClick={() => setClipPlaying((playing) => !playing)}
2431
2436
  onEnded={() => setClipPlaying(false)}
@@ -2434,7 +2439,7 @@ import { VideoHotspot } from "@ericchen1990/pano-view";
2434
2439
  />;
2435
2440
  ```
2436
2441
 
2437
- 浏览器可能拒绝非静音或非手势播放。此时 `onPlaybackStateChange` 收到 `"blocked"`,`onPlaybackError` 收到浏览器错误;宿主仍控制 `playing` 并提供显式用户操作。
2442
+ 加载或进入 VR 不会自动开始播放。就绪事件和跳转不会重置通过 controller 设置的静音与音量;修改对应 prop 或切换源时才应用新的配置。需要静音播放时显式传入 `muted`。浏览器可能拒绝非静音或非手势播放。此时 `onPlaybackStateChange` 收到 `"blocked"`,`onPlaybackError` 收到浏览器错误;宿主仍控制 `playing` 并提供显式用户操作。
2438
2443
 
2439
2444
  视频通过 `onError` 报告媒体与 poster 失败,参数含 `source: "poster" | "video"`。与 `SequenceHotspot` 相同,不会自行改变 `playing`,以保证源变更、卸载与 React StrictMode 生命周期可预测。
2440
2445
 
@@ -2718,3 +2723,52 @@ viewLimits: {
2718
2723
  ## VR 操作按钮组
2719
2724
 
2720
2725
  视频、模型和滚动支持可定制图标按钮组,仅在 VR 显示。接口、凝视行为与完整示例见[VR 控件指南](./docs/dialogs.zh-CN.md#vr-图标控件与滚动)。
2726
+
2727
+ ## WebVRSceneMenu
2728
+
2729
+ 在 `PanoViewer` 内与 `WebVR`、`Scenes` 同级挂载。仅在 WebXR、手机 VR 或桌面模拟 VR 中显示:前下方的三按钮导航可切换场景并打开弧形缩略图网格,支持凝视、指针和键盘操作。当前场景带选中框和勾选标记;再次打开时定位到当前场景所在页。
2730
+
2731
+ ```tsx
2732
+ <WebVRSceneMenu
2733
+ items={[
2734
+ { id: "hall", thumbnailUrl: "/hall.webp", title: "大厅" },
2735
+ { id: "garden", thumbnailUrl: "/garden.webp", title: "花园" },
2736
+ ]}
2737
+ activeId={activeSceneId}
2738
+ onSelect={setActiveSceneId}
2739
+ columns={4}
2740
+ rows={3}
2741
+ appearance={{ labelPlacement: "center", selectionColor: "#ffffff" }}
2742
+ />
2743
+ ```
2744
+
2745
+ `items` 复用 `PanoSceneMenuItem`。标题默认居中叠字,最多两行,超长省略;空标题回退到 ID,完整标题保留为无障碍名称。缩略图需允许跨域图片访问,加载失败时仍可通过标题选择。
2746
+
2747
+ | 参数 | 默认值/范围 |
2748
+ | --- | --- |
2749
+ | `layout` | `"compact"`(默认,原有弧形网格)、`"flat"`(平面墙)、`"arc"`(独立平卡环绕画廊) |
2750
+ | `displayMode` | `"paged"`(默认)或 `"all"`;全部模式自动增长行数,忽略 `rows`,隐藏翻页与页码 |
2751
+ | `arcAngle` | 180°;范围 60–360°,仅环绕布局使用 |
2752
+ | `columns`、`rows` | compact/flat 默认 4 列;arc 自动按每 22.5° 一列(半环 8 列,整圈 16 列);compact 列范围 2–4,新布局 2–24。分页默认 3 行,范围 1–3 |
2753
+ | `loop` | `true`,场景首尾循环;分页始终在边界停止 |
2754
+ | `closeOnSelect` | `true`;设为 `false` 可连续浏览 |
2755
+ | `follow` | `true`;仅导航跟随水平朝向,展开网格固定在空间中 |
2756
+ | `navigationPitch` | −25°;−40°至 −15° |
2757
+ | `distance`、`scale` | 2 米、1;范围 1.5–3、0.75–1.25 |
2758
+ | `fadeDurationMs` | 200;0–600ms,尊重减少动态效果设置 |
2759
+ | `showTitles` | `true` |
2760
+ | `showVisited`、`visitedLabel` | `false`、`"Visited"`;已浏览图标及其无障碍描述 |
2761
+
2762
+ 凝视时间沿用 `WebVR.cursorDwellMs`。`activeId` 是选中状态来源,`onSelect` 请求宿主切换场景;场景加载和错误处理仍由宿主负责。弹窗或 VR Setup 打开时暂时隐藏此组件。无场景时隐藏,单场景时禁用左右导航。
2763
+
2764
+ `appearance` 是有限的空间样式接口:`controlColor`(白色)、`controlBackground`(`transparent`)、`controlOpacity`(0.75,范围 0–1)、`selectionColor`(白色)、`focusColor`(`#7dd3fc`)、`selectionWidth`(4,范围 0–8)、`borderRadius`(8,范围 0–48)、`labelColor`(白色)、`labelBackground`(`transparent`)、`fontSize`(28,范围 16–48)、`labelPlacement`(`"center"` 或 `"bottom"`)。场景边框从外侧紧贴缩略图边缘。选中、凝视和键盘焦点共用 `selectionWidth`;设为零时隐藏这些边框,但保留独立的键盘焦点提示。可选的已浏览勾选图标与选中状态独立,边框宽度为零时仍显示。当前场景使用 `selectionColor`;凝视和键盘焦点使用 `focusColor`,焦点落在当前场景上时优先显示焦点颜色。数值尺寸使用参考画布像素并随整体缩放。导出 `WebVRSceneMenuProps`、`WebVRSceneMenuAppearance` 和 `DEFAULT_WEBVR_SCENE_MENU_APPEARANCE`。
2765
+
2766
+ `showVisited` 和 `visitedLabel` 沿用上述 `PanoSceneMenu` 的会话及场景就绪规则。隐藏标题(`showTitles={false}`)或缩略图加载失败时,已浏览图标仍显示;弹窗、VR Setup、翻页和重新进入 VR 均保留查看器共享记录。
2767
+
2768
+ `/webvr` 示例讲解 VR 进入、退出、能力事件与凝视激活。`/vr-scene-menu` 提供行为、布局、外观设置及当前场景标题编辑、25 场景分页演示、恢复默认,以及用于验证进出 VR 后共享浏览记录的普通菜单;`/spatial-controls` 分别讲解媒体、模型及滚动控件,`/immersive-tour` 展示完整组合。设置仅保存在当前页面状态中。
2769
+
2770
+ 悬浮导航作为紧凑的整体按钮组呈现,默认仅显示等高图标,以轻微阴影增强场景中的辨识度。
2771
+
2772
+ 平面墙与环绕画廊使用有界分块图集。全部模式保留卡片尺寸并扩展墙面;大列表可能需要更多转头浏览。打开时以当前水平朝向为中心,展开后不跟随转头,但随用户平移。新布局的关闭和翻页按钮始终位于正前方独立控制区。`/vr-scene-menu` 支持切换布局、全部/分页和环绕角度;列数留空使用自动值。
2773
+
2774
+ VR 场景标题默认不带背景,并带有轻微黑色文字阴影。菜单纹理以 2 倍分辨率绘制,使用 mipmap 与各向异性过滤;布局和命中区域保持不变。