Skip to content

Commit

Permalink
Merge branch 'gh-pages' of https://github.com/LivelyKernel/lively4-core
Browse files Browse the repository at this point in the history
… into gh-pages
  • Loading branch information
JensLincke committed Jan 2, 2024
2 parents 306faa3 + e149a70 commit 32e5c26
Show file tree
Hide file tree
Showing 8 changed files with 359 additions and 14 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ A project or branch of a project on GitHub can be checked out in multiple direct
- [lively4-core](https://lively-kernel.org/lively4/lively4-core/start.html)
- [lively4-stable](https://lively-kernel.org/lively4/lively4-stable/start.html)
- [lively4-jens](https://lively-kernel.org/lively4/lively4-jens/start.html)
- [aexpr](https://lively-kernel.org/lively4/aexpr/start.html)

The Lively4 server and GitHub sync tools can check out arbitrary projects, such as the code of [lively4-server](https://lively-kernel.org/lively4/lively4-server/) itself, or the source of a paper hosted by overleaf.

Expand All @@ -35,4 +36,4 @@ The Lively4 server and GitHub sync tools can check out arbitrary projects, such

- Reactive Programming [RP 2018](https://lively-kernel.org/lively4/lively4-seminars/RP2018/index.md)

### [Imprint](imprint.md)
### [Imprint](imprint.md)
17 changes: 15 additions & 2 deletions demos/stefan/untitled-board-game/ubg-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,23 @@ export default class Card {
this.ensureUnprintedVersion();

if (notes === undefined) {
delete this.versions.last.notes;
delete this.notes;
} else {
this.notes = notes;
this.versions.last.notes = notes;
}
}

getRating() {
return this.versions.last.rating;
}

setRating(rating) {
this.ensureUnprintedVersion();

if (rating === undefined || rating === 'unset') {
delete this.versions.last.rating;
} else {
this.versions.last.rating = rating;
}
}

Expand Down
28 changes: 28 additions & 0 deletions demos/stefan/webxr/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<meta charset='utf-8' />
<meta name='viewport' content='width=device-width, initial-scale=1, user-scalable=no' />
<meta name='mobile-web-app-capable' content='yes' />
<meta name='apple-mobile-web-app-capable' content='yes' />
<link rel='icon' type='image/png' sizes='32x32' href='favicon-32x32.png' />
<link rel='icon' type='image/png' sizes='96x96' href='favicon-96x96.png' />
<link rel='stylesheet' href='https://raw.githubusercontent.com/immersive-web/webxr-samples/main/css/common.css' />

# Immersive VR Session

<header>
<details open>
<summary>Immersive VR Session</summary>
<p>
This sample demonstrates how to use an 'immersive-vr' XRSession to
present a simple WebGL scene to an XR device. The scene is not
rendered to the page.
<a class="back" href="./">Back</a>
</p>
</details>
</header>
<main style='text-align: center;'>
<p>Click 'Enter XR' to see content</p>
</main>
<script type="module">
import {} from './webxr.js';
initXR(this);
</script>
173 changes: 173 additions & 0 deletions demos/stefan/webxr/webxr.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import {WebXRButton} from 'https://raw.githubusercontent.com/immersive-web/webxr-samples/main/js/util/webxr-button.js';
import {Scene} from 'https://raw.githubusercontent.com/immersive-web/webxr-samples/main/js/render/scenes/scene.js';
import {Renderer, createWebGLContext} from 'https://raw.githubusercontent.com/immersive-web/webxr-samples/main/js/render/core/renderer.js';
import {Gltf2Node} from 'https://raw.githubusercontent.com/immersive-web/webxr-samples/main/js/render/nodes/gltf2.js';
import {SkyboxNode} from 'https://raw.githubusercontent.com/immersive-web/webxr-samples/main/js/render/nodes/skybox.js';
import {QueryArgs} from 'https://raw.githubusercontent.com/immersive-web/webxr-samples/main/js/util/query-args.js';

// If requested, use the polyfill to provide support for mobile devices
// and devices which only support WebVR.
import WebXRPolyfill from 'https://raw.githubusercontent.com/immersive-web/webxr-samples/main/js/third-party/webxr-polyfill/build/webxr-polyfill.module.js';
if (QueryArgs.getBool('usePolyfill', true)) {
let polyfill = new WebXRPolyfill();
}

// XR globals.
let xrButton = null;
let xrRefSpace = null;

// WebGL scene globals.
let gl = null;
let renderer = null;
let scene = new Scene();
scene.addNode(new Gltf2Node({url: 'https://raw.githubusercontent.com/immersive-web/webxr-samples/main/media/gltf/space/space.gltf'}));
scene.addNode(new SkyboxNode({url: 'https://raw.githubusercontent.com/immersive-web/webxr-samples/main/media/textures/milky-way-4k.png'}));

// Checks to see if WebXR is available and, if so, queries a list of
// XRDevices that are connected to the system.
export default function initXR(context) {
// Adds a helper button to the page that indicates if any XRDevices are
// available and let's the user pick between them if there's multiple.
xrButton = new WebXRButton({
onRequestSession: onRequestSession,
onEndSession: onEndSession
});
lively.query(context, 'header').appendChild(xrButton.domElement);

// Is WebXR available on this UA?
if (navigator.xr) {
// If the device allows creation of exclusive sessions set it as the
// target of the 'Enter XR' button.
navigator.xr.isSessionSupported('immersive-vr').then((supported) => {
xrButton.enabled = supported;
});
}
}

// Called when the user selects a device to present to. In response we
// will request an exclusive session from that device.
function onRequestSession() {
return navigator.xr.requestSession('immersive-vr').then(onSessionStarted);
}

// Called when we've successfully acquired a XRSession. In response we
// will set up the necessary session state and kick off the frame loop.
function onSessionStarted(session) {
// This informs the 'Enter XR' button that the session has started and
// that it should display 'Exit XR' instead.
xrButton.setSession(session);

// Listen for the sessions 'end' event so we can respond if the user
// or UA ends the session for any reason.
session.addEventListener('end', onSessionEnded);

// Create a WebGL context to render with, initialized to be compatible
// with the XRDisplay we're presenting to.
gl = createWebGLContext({
xrCompatible: true
});

// Create a renderer with that GL context (this is just for the samples
// framework and has nothing to do with WebXR specifically.)
renderer = new Renderer(gl);

// Set the scene's renderer, which creates the necessary GPU resources.
scene.setRenderer(renderer);

// Use the new WebGL context to create a XRWebGLLayer and set it as the
// sessions baseLayer. This allows any content rendered to the layer to
// be displayed on the XRDevice.
session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });

// Get a frame of reference, which is required for querying poses. In
// this case an 'local' frame of reference means that all poses will
// be relative to the location where the XRDevice was first detected.
session.requestReferenceSpace('local').then((refSpace) => {
xrRefSpace = refSpace;

// Inform the session that we're ready to begin drawing.
session.requestAnimationFrame(onXRFrame);
});
}

// Called when the user clicks the 'Exit XR' button. In response we end
// the session.
function onEndSession(session) {
session.end();
}

// Called either when the user has explicitly ended the session (like in
// onEndSession()) or when the UA has ended the session for any reason.
// At this point the session object is no longer usable and should be
// discarded.
function onSessionEnded(event) {
xrButton.setSession(null);

// In this simple case discard the WebGL context too, since we're not
// rendering anything else to the screen with it.
renderer = null;
}

// Called every time the XRSession requests that a new frame be drawn.
function onXRFrame(t, frame) {
let session = frame.session;

// Per-frame scene setup. Nothing WebXR specific here.
scene.startFrame();

// Inform the session that we're ready for the next frame.
session.requestAnimationFrame(onXRFrame);

// Get the XRDevice pose relative to the Frame of Reference we created
// earlier.
let pose = frame.getViewerPose(xrRefSpace);

// Getting the pose may fail if, for example, tracking is lost. So we
// have to check to make sure that we got a valid pose before attempting
// to render with it. If not in this case we'll just leave the
// framebuffer cleared, so tracking loss means the scene will simply
// disappear.
if (pose) {
let glLayer = session.renderState.baseLayer;

// If we do have a valid pose, bind the WebGL layer's framebuffer,
// which is where any content to be displayed on the XRDevice must be
// rendered.
gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);

// Clear the framebuffer
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

// Loop through each of the views reported by the frame and draw them
// into the corresponding viewport.
for (let view of pose.views) {
let viewport = glLayer.getViewport(view);
gl.viewport(viewport.x, viewport.y,
viewport.width, viewport.height);

// Draw this view of the scene. What happens in this function really
// isn't all that important. What is important is that it renders
// into the XRWebGLLayer's framebuffer, using the viewport into that
// framebuffer reported by the current view, and using the
// projection matrix and view transform from the current view.
// We bound the framebuffer and viewport up above, and are passing
// in the appropriate matrices here to be used when rendering.
scene.draw(view.projectionMatrix, view.transform);
}
} else {
// There's several options for handling cases where no pose is given.
// The simplest, which these samples opt for, is to simply not draw
// anything. That way the device will continue to show the last frame
// drawn, possibly even with reprojection. Alternately you could
// re-draw the scene again with the last known good pose (which is now
// likely to be wrong), clear to black, or draw a head-locked message
// for the user indicating that they should try to get back to an area
// with better tracking. In all cases it's possible that the device
// may override what is drawn here to show the user it's own error
// message, so it should not be anything critical to the application's
// use.
}

// Per-frame scene teardown. Nothing WebXR specific here.
scene.endFrame();
}
22 changes: 20 additions & 2 deletions src/components/widgets/ubg-cards-editor.html
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@
#form-layout {
display: grid;
grid-template-columns: min-content auto 2.5in;
grid-template-rows: repeat(7, auto) 1fr auto .5fr auto;
grid-template-rows: repeat(7, auto) 1fr auto auto .5fr auto;
grid-template-areas:
"isPrinted-key isPrinted-value preview"
"id-key id-value preview"
Expand All @@ -139,6 +139,7 @@
"vp-key vp-value preview"
"text-key text-value preview"
"tags-key tags-value preview"
"rating-key rating-value preview"
"notes-key notes-value preview"
"art-key art-value preview"
;
Expand Down Expand Up @@ -217,6 +218,11 @@
.tag:focus {
background: #32cd3280;
}
#rating {
height:
}


</style>
<div id='form-layout'>
<span class='key' style='grid-area: isPrinted-key;'>is printed</span>
Expand All @@ -235,14 +241,26 @@
<input id='vp' class='value' style='grid-area: vp-value;' />
<span class='key' style='grid-area: text-key;'>text</span>
<textarea id='text' class='value' style='grid-area: text-value;'></textarea>
<span class='key' style='grid-area: tags-key;'>tags</span>
<span id='tags' class='value' style='grid-area: tags-value;'>
<input-combobox id="tags-input"></input-combobox><span id="tags-list"></span>
</span>
<span class='key' style='grid-area: rating-key;'>rating</span>
<form id="rating" class='value' style='grid-area: rating-value;'>
<input type="radio" id="choiceKeep" name="rating" value="keep" />
<label for="choiceKeep">keep</label>
<input type="radio" id="choiceUnsure" name="rating" value="unsure" />
<label for="choiceUnsure">unsure</label>
<input type="radio" id="choiceRemove" name="rating" value="remove" />
<label for="choiceRemove">remove</label>
<input type="radio" id="choiceUnset" name="rating" value="unset" />
<label for="choiceUnset">unset</label>
</form>
<span class='key' style='grid-area: notes-key;'>notes</span>
<textarea id='notes' class='value' style='grid-area: notes-value;'></textarea>
<span class='key' style='grid-area: art-key;'>art</span>
<input id='art' class='value' style='grid-area: art-value;' />
<span class='key' style='grid-area: tags-key;'>tags</span>

<div id='preview-container'>
<div id='preview'>
<div id='previewViewer'></div>
Expand Down
35 changes: 34 additions & 1 deletion src/components/widgets/ubg-cards-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,15 @@ export default class UBGCardsEditor extends Morph {
}
this.$text.addEventListener('keydown', evt => this.keydown$text(evt), false);
this.$tagsInput.addEventListener('keydown', evt => this.keydown$tagInput(evt), false);

this.get('#rating').addEventListener('change', evt => {
if (evt.target.name === 'rating') {
this.modify$rating(evt)
}
});
}

initSlider() {

}

get ubg() {
Expand Down Expand Up @@ -227,6 +235,9 @@ export default class UBGCardsEditor extends Morph {
get $tagsList() {
return this.get('#tags-list');
}
get $rating() {
return this.get('#rating');
}
get $notes() {
return this.get('#notes');
}
Expand Down Expand Up @@ -497,6 +508,27 @@ export default class UBGCardsEditor extends Morph {
}
}

modify$rating(evt) {
const rating = evt.target.value;
if (rating === '') {
this.card.setRating();
} else {
this.card.setRating(rating);
}

this.propagateChange()
}
display$rating() {
const rating = this.card.getRating() || 'unset';

const selectedOption = this.$rating.querySelector(`[value='${rating}']`)
if (selectedOption) {
selectedOption.checked = true;
} else {
lively.warn('Unknown rating ' + rating)
}
}

modify$notes(evt) {
const notes = this.$notes.value;
if (notes === '') {
Expand Down Expand Up @@ -570,6 +602,7 @@ export default class UBGCardsEditor extends Morph {
this.display$vp();
this.display$text();
this.display$tags();
this.display$rating();
this.display$notes();
this.display$art();
this.display$isPrinted();
Expand Down
8 changes: 7 additions & 1 deletion src/components/widgets/ubg-cards-entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,13 @@ export default class UBGCardEntry extends Morph {

const v = card.versions.last;

this.get('#id').innerHTML = card.id || '???';
const id = this.get('#id')
id.style.borderLeft = '5px solid ' + ({
keep: 'green',
unsure: 'yellow',
remove: 'red',
}[card.getRating()] || 'gray');
id.innerHTML = card.id || '???';

const type = v.type && v.type.toLowerCase();
this.get('#type').className = {
Expand Down
Loading

0 comments on commit 32e5c26

Please sign in to comment.