-
Notifications
You must be signed in to change notification settings - Fork 386
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deferred session requests #256
Conversation
explainer.md
Outdated
@@ -478,60 +478,59 @@ function onDrawFrame() { | |||
} | |||
``` | |||
|
|||
### Presenting automatically when the user interacts with the headset | |||
### Responding to a reset pose |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I moved the automatic presentation section below this one to help it flow better with the navigation section, but it's made the diff kind of ugly to read. The entire "Responding to a reset pose" section is unchanged.
Went over this proposal at length today on the implemetors call. A few things that were brought up:
I may have missed logging some of the subjects we covered, but I think those were the major points. |
Requested by @NellWaliczek. This is for the sake of clarifying things for TAG review if we don’t get a better solution in place before they look at the explainer, since we know this ISN’T the right way to handle this. Ideally we’ll put it back in with #256 or a similar PR.
Requested by @NellWaliczek. This is for the sake of clarifying things for TAG review if we don’t get a better solution in place before they look at the explainer, since we know this ISN’T the right way to handle this. Ideally we’ll put it back in with #256 or a similar PR.
…iner Requested by @NellWaliczek. This is for the sake of clarifying things for TAG review if we don’t get a better solution in place before they look at the explainer, since we know this ISN’T the right way to handle this. Ideally we’ll put it back in with #256 or a similar PR.
With this new promise approach, I think not being able to unsubscribe to the deferral for activation is a step backwards over having a plain old event handler. On Facebook, I typically have a steady stream of 360 videos in my feed due to the people I follow. Clicking on one of these videos renders a larger version over the top of the feed. If would be great if, in this mode, putting your phone in a headset triggered automatic WebVR. However, Facebook wouldn’t want automatic WebVR if there is more than one video on the page and certainly not if there are zero videos on the page. The same can be said for real estate websites or other “progressive enhancement” pages where automatic WebVR is not always the right thing to do. I think we need to provide more flexibility than what is proposed. Cancelling the deferral by calling endSession on promise resolution would likely entail more system bringup/teardown and is awkward from an API perspective. |
Thanks for the comment. I agree that the lack of a method to cancel the handler is problematic, and I appreciate you bringing it up since I hadn't considered it before. I'd like to talk over some options with the developers on my end that were requesting a change in the first place, but I'd appreciate suggestions of alternative APIs in the meantime! For the moment it seems like going back to an event handler is the least problematic route. |
I agree event handlers seem like the best option in lieu of the current proposal. However, I would like to hear what @NellWaliczek and her colleagues discuss early next week on the topic. |
…iner Requested by @NellWaliczek. This is for the sake of clarifying things for TAG review if we don’t get a better solution in place before they look at the explainer, since we know this ISN’T the right way to handle this. Ideally we’ll put it back in with #256 or a similar PR.
5045aa0
to
5adae63
Compare
Resurrecting this thread following a discussion I had with @RafaelCintron at a Khronos face to face last week. I had been doing some research on this and bounced an idea off of him, and he responded with a simpler idea. I think both ideas have merit and both have tradeoffs, so I wanted to outline them here for discussion: Brandon's ProposalI was reading about the direction that the Anyway, I could see this pattern being successfully applied to the concept of deferred sessions in a very similar manner: let controller = new VRSessionRequestController();
controller.deferUntilActivate = true; // Kinda don't care what the syntax is here.
vrDevice.requestSession({ exclusive: true, signal: controller.signal })
.then( /*...*/ )
.catch( (err) => {
// If the request is aborted you'll end up with with err being an AbortError.
});
function onSomeCriteria() {
// Oh noes! Some criteria has been fulfilled and now it is no longer appropriate
// to start presenting on activate. Better cancel the request!
controller.abort();
}; Pros:
Cons:
Rafael's ProposalUpon me outlining this idea, Rafael proposed a more straightforward but possibly more limiting route: Have a single vrDevice.requestSession({ exclusive: true, deferTill: 'activate' })
.then( /*...*/ )
.catch( (err) => {
// Again, canceling before the session is fulfilled lands you here.
});
vrDevice.requestSession({ exclusive: true, deferTill: 'navigate' }).then( /*...*/ );
function onSomeCriteria() {
// Oh noes! Some criteria has been fulfilled and now it is no longer appropriate
// to start presenting on activate/navigate. Better cancel the request(s)!
vrDevice.cancelSessionRequests();
}; Additionally he suggested that under this system multiple requests with the same creation criteria could return the same promise for each call. This is indeed simpler: it's only one additional function instead of a couple of new interfaces. It does lack some fine grained controls, though. A library that puts out a deferred session request may randomly have it cancelled by a developer who was unaware that it was even requested and instead was trying to manage their own session request lifetime. Pros:
Cons:
Anyway, as I said I think both variants have merit so I'd love some additional opinions on which of these approaches you would lean towards (or suggestions for a different approach all together!) |
The 2nd, "Rafael's Proposal", feels better to me, assuming that everyone is comfortable with pushing library interaction up higher into the stack |
David mentioned at one point that if the abort controller is the way the web platform is going we should follow it. Wanted to point out that that does seem to be the case (exhibit A). |
@toji know this is a bit old, but do you need this reviewed, or should I wait on updates? |
4096897
to
c228adb
Compare
Following up from conversation on the most recent call, I've refactored this change to account for the proposed transition to an One outstanding question for me that this change doesn't address (and which I think is a matter of platform expectations.) If a developer creates a standard Anyway, comments on that issue or the rest of the change welcome! Tried to be fairly explicit in the text about various edge cases but that can lead to dense and hard to parse prose so please let me know if something is confusing. |
I reached out to @jakearchibald about this, given that he was one of the developers involved with the creation of
const controller = new AbortController();
const signal = controller.signal;
requestSession({
waitUntilActivate: true,
signal
}).then(() => {
// …
});
Which, now that it's been pointed out, seems really obvious to me and I'm not sure why I didn't take that approach in the first place. 😓 It's definitely simpler in terms of IDL within our spec. I'll update the PR to reflect that momentarily. |
PR is now updated to account for the above change. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks great. my feedback is mostly on minor typos, questions about gaps in description of intent and lifecycle.
I’m a big fan of the approach you’ve taken here. thanks for incorporating everyone’s feedback here. this is one of the last big changes to getting first-class VR navigation and UX 👍
explainer.md
Outdated
@@ -591,6 +591,90 @@ vrSession.addEventListener('resetpose', vrSessionEvent => { | |||
}); | |||
``` | |||
|
|||
### Presenting automatically when the user interacts with the headset | |||
|
|||
Many VR devices have some way of detecting when the user has put the headset on or is otherwise trying to use the hardware. For example: an Oculus Rift or Vive have proximity sensors that indicate when the headset is being worn. And a Daydream device uses NFC tags to inform the phone when it's been placed in a headset. This is referred to as the `VRDevice` being "activated", and depending on context it may represent the user showing a clear intent to begin using VR. Many WebVR application may want to begin presenting automatically in these scenarios. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
first sentence could be simplified to Many VR devices detect when the headset is being worn or used by the user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change Many
to A
(or use plural applications
)
explainer.md
Outdated
|
||
Many VR devices have some way of detecting when the user has put the headset on or is otherwise trying to use the hardware. For example: an Oculus Rift or Vive have proximity sensors that indicate when the headset is being worn. And a Daydream device uses NFC tags to inform the phone when it's been placed in a headset. This is referred to as the `VRDevice` being "activated", and depending on context it may represent the user showing a clear intent to begin using VR. Many WebVR application may want to begin presenting automatically in these scenarios. | ||
|
||
In order to start presenting when the `VRDevice` is activated pages can request a deferred session. To request a deferred session the option `{ waitForActivate: true }` is passed into the `requestSession` call. When a session is requested with `waitForActivate` the request will remain outstanding until the `VRDevice` is activated, at which point the promise will resolve with the requested session (or reject, if necessary.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add a comma after activated
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
outstanding
-> pending
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.)
-> ).
explainer.md
Outdated
|
||
In order to start presenting when the `VRDevice` is activated pages can request a deferred session. To request a deferred session the option `{ waitForActivate: true }` is passed into the `requestSession` call. When a session is requested with `waitForActivate` the request will remain outstanding until the `VRDevice` is activated, at which point the promise will resolve with the requested session (or reject, if necessary.) | ||
|
||
Deferred sessions must be exclusive and will not be fulfilled if there is already an exclusive session active for the VR hardware device when the activation action occurs. Deferred requests do not need to be made within a user gesture. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what happens if an initial activation and deactivation happen before the requestSession
call is made (when {waitForActivate: true}
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My intent would be that the activation is ignored and we would wait till the next one to resolve the session. We could also allow it to pick up an activation that has happened a couple of seconds prior to the request being made, but I'm not sure if that's going to be a commonly encountered scenario.
explainer.md
Outdated
vrDevice.requestSession({ exclusive: true, waitForActivate: true }).then(OnSessionStarted); | ||
``` | ||
|
||
Once the deferred session request has been fulfilled or rejected a new deferred session request will need to be issued if the page wishes to respond to future activation actions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add a comma after rejected
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is kind of in line with my question above, but doesn’t cover that exact case of activate -> deactivate prior to
explainer.md
Outdated
|
||
Once the deferred session request has been fulfilled or rejected a new deferred session request will need to be issued if the page wishes to respond to future activation actions. | ||
|
||
To detect when the user removes the headset, at which point the page may want to end the session, listen for the `deactivate` event. Note that not all devices capable of detecting activation can reliable detect deactivation, so pages are not guaranteed to receive an associated deactivate event for each activation action. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reliable
-> reliably
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’d add backtick code marks for deactivate
explainer.md
Outdated
waitForActivate: true, | ||
signal: abortController.signal }) | ||
.then(OnSessionStarted) | ||
.catch((reason) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
out of curiosity, would the AbortController
-backed signal
always throw or reject?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you remove the parentheses around the argument
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Um... not entirely sure what you're asking about the throw/reject. The abort signal causes the promise to reject when it's controller's abort
method is called if it has not already resolved.
explainer.md
Outdated
if (abortController.signal.aborted) { | ||
console.log("Session request was canceled by the page."); | ||
} else { | ||
console.log("Session request was reject by the system: " + reason); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would do one of the following:
“, reason);
“, reason.message);
explainer.md
Outdated
.catch((reason) => { | ||
if (abortController.signal.aborted) { | ||
console.log("Session request was canceled by the page."); | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: this conditional logic doesn’t necessarily mean the “system” rejected it. there could’ve been an error thrown in OnSessionStarted
.
explainer.md
Outdated
|
||
```js | ||
// Requests that a session be created when the device is activated. | ||
let abortController = new AbortController(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it might be nice to show another example to show that you can listen for an event as well:
abortController.addEventListener('abort', evt => {
console.log('Aborted');
});
explainer.md
Outdated
vrDevice.requestSession({ | ||
exclusive: true, | ||
waitForActivate: true, | ||
signal: abortController.signal }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
feel free to put the brace on the next line, for clarity
Addressed your comments, and had one outstanding question (repeated here since GH collapsed the comment): Is there a downside to moving the |
I actually like that a lot. it cleans up the interfaces. my only concern would be that developers probably don’t want to manage different Promises for the VR Sessions. it’s nice to always have one place to add your event listener. I can’t think of a common use case where this new change would be cumbersome. 👍 |
Okay then, done! I'm feeling pretty good about the general state of this feature but I'm waiting to merge because @NellWaliczek let me know that Microsoft had some feedback on this change incoming. |
Talked with @NellWaliczek about this extensively at TPAC this week, which helped me better understand Microsoft's position on this. I'll recap a bit of it here prior to updating the PR for context. One big Microsoft is concerned about the concept of "activation" being potentially being triggered when inappropriate. For example: When you have a couple of browser windows with some WebVR content on them but they're not necessarily what the user is focused on at the moment. Should putting on the headset trigger those pages, or the default system "home" environment? If you do launch VR content which of the browser pages takes priority? Will that be consistent across browsers and platforms? It's something that may make sense on some devices that are more modal with VERY strong VR entry signals (placing and Android device into a viewer), but not platforms that are more multitasking friendly. Which leads to a secondary concern of activate signals being applied unevenly, which may lead developers to make bad platform-wide assumptions. For example: We've already seen at least one example of a fairly high-profile site that was inaccessible from Edge because they relied solely on "activate" events to trigger VR instead of providing a button on the page. This is definitely a behavior we don't want to encourage. For my part, I still think that the concept of activate has merit in a couple of different areas:
But given Microsoft's concerns I'm willing to defer (😏) that part of the deferred sessions proposal till we can have some further discussion. Navigation, on the other hand, seems to be a universally agreed upon "good idea", so any concerns there come down to behavioral details. I think that navigate as it's been presented here should work out just fine, but Nell and talked about a few extended uses and considerations for it that would be good to capture here (and potentially in the explainer as well, where appropriate.) For one, UAs could enable "Deep Links" to pages which start up immediately in WebVR mode with the proposed navigation pattern. It would work like so: Page attempts to request a navigation session but it's rejected immediately because the criteria for navigation hasn't been satisfied. Nevertheless, the browser can remember that the page did make the attempt and when the user goes to create a bookmark or add to homescreen or what have you they can be given an additional option in the dialog:
Given that's UA behavior we can't really spec it, but maybe some non-normative text is in order. Another interesting option would be the ability to have links on a 2D page be given some markup that indicates that they want to launch the linked page in VR if available. It would be useful for content galleries that want to have a 2D page tying together multiple VR experiences. This may look something like: <a href="/webvr_example_1.html" target="_vr">View Example 1</a> The UA of course would have a lot of latitude around how to handle that. If the system doesn't have VR capabilities then it would just function as a normal link, or it could choose not to honor the request if the user has previously denied the origin the ability to enter VR automatically. The UA could also give visual indicators that the link will jump into VR if needed, such as a different mouse cursor upon hover. Anyway, that's a slice of the conversation we had, there's a few other tweaks that I'll try and work into the explainer text too. That'll likely be incoming beginning of next week. |
Okay, for the time being I've stripped the concepts of activate and deactivate out of the explainer, and along with them the necessity for the Reworked the text to be navigation-centric, but I've left out the previously described link target behavior and non-normative text about deep links because I feel that's better left to a follow-up PR as well, where the behavior can be discussed in a more focused way. Please take a look at the current text and let me know if there's anything that should be fixed prior to merging! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for accommodating my request to focus this PR on just the navigation scenarios! I've added a few comments that may have gotten lost in the cracks of our conversation in person last week :)
explainer.md
Outdated
|
||
WebVR applications can, like any web page, link to other pages. In the context of an exclusive `VRSession`, this is handled by setting `window.location` to the desired URL when the user performs some action. If the page being linked to is not VR-capable the user will either have to remove the VR device to view it or the page could be shown as a 2D page in a VR browser. | ||
|
||
If the page being navigated to is VR capable, however, it's frequently desirable to allow the user to immediately create an exclusive `VRSession` for that page as well, so that the user feels as though they are navigating through a single continuous VR experience. To allow this the UA tracks when a page navigates without ending an active exclusive session first. This flags the newly loaded page as "VR navigable", which activates a couple of new behaviors to allow for the desired navigation experience. UAs may also place additional restrictions on what conditions are considered VR navigable, such as restricting it to only same-origin URLs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not that it is a guarantee that developers will pay attention to this, but can we add language indicating that it's important for pages to have an "Enter VR" button even when also requesting the "on navigate" session?
explainer.md
Outdated
|
||
WebVR applications can, like any web page, link to other pages. In the context of an exclusive `VRSession`, this is handled by setting `window.location` to the desired URL when the user performs some action. If the page being linked to is not VR-capable the user will either have to remove the VR device to view it or the page could be shown as a 2D page in a VR browser. | ||
|
||
If the page being navigated to is VR capable, however, it's frequently desirable to allow the user to immediately create an exclusive `VRSession` for that page as well, so that the user feels as though they are navigating through a single continuous VR experience. To allow this the UA tracks when a page navigates without ending an active exclusive session first. This flags the newly loaded page as "VR navigable", which activates a couple of new behaviors to allow for the desired navigation experience. UAs may also place additional restrictions on what conditions are considered VR navigable, such as restricting it to only same-origin URLs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This flags the newly loaded page as "VR navigable", which activates a couple of new behaviors to allow for the desired navigation experience.
This phrasing doesn't read super clearly to me...
explainer.md
Outdated
|
||
If the page being navigated to is VR capable, however, it's frequently desirable to allow the user to immediately create an exclusive `VRSession` for that page as well, so that the user feels as though they are navigating through a single continuous VR experience. To allow this the UA tracks when a page navigates without ending an active exclusive session first. This flags the newly loaded page as "VR navigable", which activates a couple of new behaviors to allow for the desired navigation experience. UAs may also place additional restrictions on what conditions are considered VR navigable, such as restricting it to only same-origin URLs. | ||
|
||
In order to start presenting automatically when a page is VR navigable, pages can make a "deferred" session request. To request a deferred session the option `{ waitForNavigate: true }` is passed into the `requestSession` call. If the page is VR navigable, the request will be resolved when the page is ready to begin presenting. If the page is not VR navigable the request will reject immediately. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it really "deferred"? Or can we simply just remove the requirement for the session initiation to be performed via a user gesture if invoked early enough in the new page's lifetime? If so, what is "early enough"?
explainer.md
Outdated
|
||
If the page being navigated to is VR capable, however, it's frequently desirable to allow the user to immediately create an exclusive `VRSession` for that page as well, so that the user feels as though they are navigating through a single continuous VR experience. To allow this the UA tracks when a page navigates without ending an active exclusive session first. This flags the newly loaded page as "VR navigable", which activates a couple of new behaviors to allow for the desired navigation experience. UAs may also place additional restrictions on what conditions are considered VR navigable, such as restricting it to only same-origin URLs. | ||
|
||
In order to start presenting automatically when a page is VR navigable, pages can make a "deferred" session request. To request a deferred session the option `{ waitForNavigate: true }` is passed into the `requestSession` call. If the page is VR navigable, the request will be resolved when the page is ready to begin presenting. If the page is not VR navigable the request will reject immediately. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we be more specific about when in the page lifetime the promise will be expected to fulfill? Will the DOM already be fully set up (for grabbing a canvas object for example)? Or do we want this to be earlier so fewer resources need to be previously spun up?
explainer.md
Outdated
vrDevice.requestSession({ exclusive: true, waitForNavigate: true }).then(OnSessionStarted); | ||
``` | ||
|
||
> **Non-normative Note:** The UA should provide a visual transition between the two pages. At minimum the previous page should fade to black and the new one should fade in from black. Additionally, if the UA cannot display pages in VR it is recommended that it should instruct the user to remove the headset once the UA switches to displaying a 2D page. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At minimum the previous page should fade to black and the new one should fade in from black.
Too prescriptive :) What if the user agent wants to fade to white?
explainer.md
Outdated
@@ -652,6 +670,7 @@ partial interface Navigator { | |||
|
|||
dictionary VRSessionCreationOptions { | |||
boolean exclusive = false; | |||
boolean waitForNavigate = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not clear on why this parameter would actually be necessary. I get that it might be left over from the activation design, but I'm not see the value it's adding given the current design... am I missing something totally obvious? ^_^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, for one I want to leave the door open for activation and I think this establishes the right pattern for it. (I know you'd rather not have activation be a thing, but I'm not giving up on it yet.)
Secondly, I'm not really comfortable with the idea of "Make a request that would otherwise fail but if you do it within this special timeframe it might sometimes succeed. Maybe." In my opinion the API should be more explicit in it's intent than that. It would feel less weird to me if we said developers could add a listener for a vrnavigateready
event and you can make session requests within that callback, but that's the model that WebVR 1.1 uses which we are explicitly trying to get away from because adding the event listener is not a strong guarantee for the browser that session creation will happen.
I hear what you're saying about being more clear about the time span that this call can validly be made in, and I'll update the doc to account for it.
Okay, made some more updates based on Nell's feedback, but I've kept the need for an explicit |
@toji just so I understand what's being proposed here... Page A: loads in UA
Page A: unloads
Page B: loads
If Page B is NON-VR (not what this PR is about, but still interesting to consider)
If Page B is VR-capable -- what this PR is try to solve... To avoid "falling out of VR" (because of the user-interaction requirement to start a session) resulting in the user swapping (temporarily) to one of the previously mentioned 2d experience, the idea is to continue a VR experience by re-engaging Page B's experience ASAP while the user still has the headset in place. The proposal is to have a flag that is passed to Surely this can't be the only signal, since in that case Page A would also use this and try to bypass the user-interaction requirement which was put in place for good reason. It seems totally reasonable to me that the UA could resume the VR experience for Page B automatically, and does not need this programmatic signal from the web developer to enable this scenario to work. The UA already has all the state info it needs to make this decision (e.g., is the headset still 'activated', receives the request to Given the very unpredictable latency involved (and load times) of navigation, the user might be left waiting for quite a while before a Thanks for letting me brain-dump here. |
Thanks for your comments, @travisleithead! In general I would say your assessment is correct, though we would likely treat Cardboard differently than you indicated. On Google's side I would expect the transitions to look something like this: Cardboard & Daydream, VR-to-VR:
Daydream, VR-to-2D:
Cardboard, VR-to-2D:
We haven't determined our preferred flow for desktop headsets yet. Regarding the flag being seen as unnecessary, I understand what you and Nell are getting at and I agree that in this isolated example it's unnecessary. I do have concerns about how that behavior will mix with other desired flags in the future, though. For example, even though it's been removed from the patch for now I am still planning on adding the
However, if I call that before
Which certainly works, but feels strange to me. I find the explicit variant much easier to understand regarding developer intent:
That's really just syntactic sugar at the end of the day, and I wouldn't consider it a blocker. Still, I'm curious if it changes your opinion. |
Oh, one other benefit of having an explicit flag: It allows us to communicate more useful error messages to the developer calls it outside the page load window.
instead of
|
16f7fb1
to
1c7572f
Compare
Rebased this (surprisingly old) pull request and renamed all the VR things to XR. Didn't change the basic substance, though, because there was never a followup to my previous comments. Would like to discuss merging this on today's call. |
Most comments addressed, minus ongoing waitForNavigate
discussion
explainer.md
Outdated
|
||
WebXR applications can, like any web page, link to other pages. In the context of an exclusive `XRSession`, this is handled by setting `window.location` to the desired URL when the user performs some action. If the page being linked to is not XR-capable the user will either have to remove the XR device to view it or the page could be shown as a 2D page in a XR browser. | ||
|
||
If the page being navigated to is XR capable, however, it's frequently desirable to allow the developer to immediately create an exclusive `XRSession` for that page as well, so that the user feels as though they are navigating through a single continuous XR experience. To allow this the UA tracks when a page navigates without ending an active exclusive session first. This flags the newly loaded page as "XR navigable". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last two sentences are a bit confusing. I think being more explicit and consistent about the actors would help.
explainer.md
Outdated
|
||
If the page being navigated to is XR capable, however, it's frequently desirable to allow the developer to immediately create an exclusive `XRSession` for that page as well, so that the user feels as though they are navigating through a single continuous XR experience. To allow this the UA tracks when a page navigates without ending an active exclusive session first. This flags the newly loaded page as "XR navigable". | ||
|
||
In order to start presenting automatically when a page is XR navigable, pages can make a "deferred" session request. To request a deferred session the option `{ waitForNavigate: true }` is passed into the `requestSession` call. If the page is XR navigable, the request will be resolved when the page is ready to begin presenting. If the page is not XR navigable the request will reject immediately. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the request will be resolved when the page is ready to begin presenting.
"The page" doesn't determine when it is ready. The UA must make this decision based on something. We should specify what that is. This is especially important to analyze the lifetime impacts and what applications can expect.
It's probably also worth (non-normatively) addressing what pages should do to ensure a smooth transition. For example, display frames quickly and defer work to post-presentation. This is important because the user experience may be different from a page that normally loads a magic window and has loaded the resources before calling requestSession()
.
explainer.md
Outdated
|
||
If the page being navigated to is XR capable, however, it's frequently desirable to allow the developer to immediately create an exclusive `XRSession` for that page as well, so that the user feels as though they are navigating through a single continuous XR experience. To allow this the UA tracks when a page navigates without ending an active exclusive session first. This flags the newly loaded page as "XR navigable". | ||
|
||
In order to start presenting automatically when a page is XR navigable, pages can make a "deferred" session request. To request a deferred session the option `{ waitForNavigate: true }` is passed into the `requestSession` call. If the page is XR navigable, the request will be resolved when the page is ready to begin presenting. If the page is not XR navigable the request will reject immediately. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"deferred session" is introduced as a term here and used below.
The session isn't really deferred. I think it's the request that is deferred, which is consistent with "deferred" session request
.
If a term is going to be coined, maybe it should be included in the section header. For example, "Page navigation & deferred session requests."
explainer.md
Outdated
|
||
If the page being navigated to is XR capable, however, it's frequently desirable to allow the developer to immediately create an exclusive `XRSession` for that page as well, so that the user feels as though they are navigating through a single continuous XR experience. To allow this the UA tracks when a page navigates without ending an active exclusive session first. This flags the newly loaded page as "XR navigable". | ||
|
||
In order to start presenting automatically when a page is XR navigable, pages can make a "deferred" session request. To request a deferred session the option `{ waitForNavigate: true }` is passed into the `requestSession` call. If the page is XR navigable, the request will be resolved when the page is ready to begin presenting. If the page is not XR navigable the request will reject immediately. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: comma after the last XR navigable
.
explainer.md
Outdated
|
||
In order to start presenting automatically when a page is XR navigable, pages can make a "deferred" session request. To request a deferred session the option `{ waitForNavigate: true }` is passed into the `requestSession` call. If the page is XR navigable, the request will be resolved when the page is ready to begin presenting. If the page is not XR navigable the request will reject immediately. | ||
|
||
Deferred sessions must be exclusive. If a non-exclusive deferred session is requested the promise will immediately be rejected. Deferred requests do not need to be made within a user gesture. Only one session request with the `waitForNavigate` option is allowed per page and subsequent requests using `waitForNavigate` will be rejected immediately. The page's XR navigable state must expire after all listeners for the `window`'s `load` event have fired. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: comma after requested
.
explainer.md
Outdated
|
||
WebXR applications can, like any web page, link to other pages. In the context of an exclusive `XRSession`, this is handled by setting `window.location` to the desired URL when the user performs some action. If the page being linked to is not XR-capable the user will either have to remove the XR device to view it or the page could be shown as a 2D page in a XR browser. | ||
|
||
If the page being navigated to is XR capable, however, it's frequently desirable to allow the developer to immediately create an exclusive `XRSession` for that page as well, so that the user feels as though they are navigating through a single continuous XR experience. To allow this the UA tracks when a page navigates without ending an active exclusive session first. This flags the newly loaded page as "XR navigable". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"XR navigable" sounds like a property of the page, but this is really state within the UA. I think we should find another term that reflects "allowed to present on navigation."
explainer.md
Outdated
|
||
WebXR applications can, like any web page, link to other pages. In the context of an exclusive `XRSession`, this is handled by setting `window.location` to the desired URL when the user performs some action. If the page being linked to is not XR-capable the user will either have to remove the XR device to view it or the page could be shown as a 2D page in a XR browser. | ||
|
||
If the page being navigated to is XR capable, however, it's frequently desirable to allow the developer to immediately create an exclusive `XRSession` for that page as well, so that the user feels as though they are navigating through a single continuous XR experience. To allow this the UA tracks when a page navigates without ending an active exclusive session first. This flags the newly loaded page as "XR navigable". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we keep using a term like "XR navigable," I suggest italicizing it in subsequent uses or otherwise making it clear that this is a special state.
@@ -666,6 +689,7 @@ partial interface Navigator { | |||
|
|||
dictionary XRSessionCreationOptions { | |||
boolean exclusive = false; | |||
boolean waitForNavigate = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
waitForNavigate
is an odd name since the navigate has already occurred by the time the page starts running code, right?
We should probably use a term related to whatever it means for the UA/page to be "ready to begin presenting."
@@ -605,6 +605,29 @@ xrSession.addEventListener('resetpose', xrSessionEvent => { | |||
}); | |||
``` | |||
|
|||
### Page navigation | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This section doesn't address how the user agent behaves before/during the navigation other than to track "when a page navigates without ending an active exclusive session first."
Specifically, the UA needs to know whether to remain in XR presentation or transition to 2D. As written, I think the UA would always need to remain in XR presentation until "after all listeners for the window
's load
event have fired." That would be different from navigating from all other pages. We might need some type of HTTP header to trigger this behavior. We should talk to navigation folks.
@@ -605,6 +605,29 @@ xrSession.addEventListener('resetpose', xrSessionEvent => { | |||
}); | |||
``` | |||
|
|||
### Page navigation | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that headset activation was removed. While it doesn't have to be in this PR, I think we should know how we want to handle that (i.e., have a companion PR) before we effectively commit to an API shape for "auto presentation" scenarios.
Sorry to revive this issue, but I didn't see any information about the origin URL from where the deferred session has been called. How the target website can know this information, to create a "go back" portal by example? |
This issue needs reviving. :) The origin URL should be handled by the existing |
So yeah I was wondering if document.referrer was "strong enough" to be used. By example, clicking in the email I received from your answer to this issue, the referrer is empty. Isn't there a risk that'll happen as well through link traversal? Also, I've some concerns:
And finally I was wondering if we could identify WebXR websites in an automated way, through some meta tag or something, to allow indexation through some search portal. Also it's the main issue I found about navigating from one experience to an other, but maybe some of those question belong to new issues. If so please let me know, I'd be happy to create new ones! |
I would tend to assume, given the myriad issues around user privacy and the web, that we should stick to the semantics of Don't UAs already have a mechanism to "go back"? Shouldn't we just use that? As for the "preview portal" we've worked on demos of that in the past (@cvan?) , and it should definitely be possible. We don't really want to download and run entire pages to generate the world through the portal, so this may require something like meta tags, glTF preview models, etc. |
We should be sure that the initiation of any deferred sessions carry with them sufficient privileges/"engagement" to enable audio/video, such that it does not require additional gestures. Context: Chrome's autoplay policy change in m66. The MEI scoring here may already be satiated, but a use-case that should be supported by deferred sessions. |
Closing this as there's now a new proposal in #383 |
This is an update to how we would handle device activation events, which I alluded to in #194. I've also combined it with some of the navigation concepts from #247, which appears to be another magical GitHub PR closure. (I'm doing something weird with my branches, I guess.)
The intent behind this style of session request is to make UA transition logic more predictable. By making a deferred request the UA knows that it can switch to presentation mode when the criteria is fulfilled, so there's no bouncing back and forth into Javascript and hoping that the page calls
requestSession
in response to an event firing. It's definitely something we've seen would be beneficial in Chrome.I have some concerns out the gate that I'd like others opinions on: Not sure if the terminology (deferred session request, deferTill, etc) is right for the functionality. It especially feels a bit odd in the "navigate" case. Also it's awkward to me that
activate
is this new deferred thingy whiledeactivate
is still a normal event. Finally, I kinda wonder whether or not we needgetNavigationDevice
. You could technically get by with just iterating through all of the devices and requesting a deferred navigate session against them. It would reject immediately on anything that wasn't valid for navigation. That feels a little ugly, but in reality most of the time you'd only have one device anyway. So maybe that's good enough for V1?So I'd love feedback on any of that, or anything else that you've got thoughts on. Thanks!
Preview | Diff