brianpeiris/aframe-markdown 19
Render Markdown using SDF text in A-Frame.
brianpeiris/aframe-textarea-component 14
A Textarea component for A-Frame
Realtime facetracking and morph target animation demo
It's just a thing, you know?
Future of Software Engineering with Consumer Virtual Reality
Building Blocks for the VR Web
🎨 Paint in VR in your browser.
startedlo-th/uil
started time in 19 hours
pull request commentbalderdashy/sails-generate
[patch] Remove "embeds" header from model template
Yeah, my google-fu is failing me because I can't find any references to the concept of "embeds" in relation to sails. Presumably if this header is important, the concept is worth calling out in the docs. At least a definition would be helpful.
comment created time in a day
pull request commentbalderdashy/sails-generate
[patch] Remove "embeds" header from model template
Ah, gotcha. Thanks for the reply. It's still unclear to me what an "embed" is and how it differs from a regular attribute. I suppose this might be a section under the existing Attributes documentation, unless Embeds are unique and important enough concept to be documented separately under the Models and ORM docs.
comment created time in a day
PR opened balderdashy/sails-generate
I'm new to sails, but as far as I can tell, the concept of "embeds" is an old one that is no longer mentioned in the current documentation, so I'd suggest removing it from the model generator template.
pr created time in 2 days
push eventbrianpeiris/sails-generate
commit sha 6284b3daf409474d9d6ef879ea6708290aca706e
Remove "embeds" header from model template I'm new to sails, but as far as I can tell, the concept of "embeds" is an old one that is no longer mentioned in the current documentation, so I'd suggest removing it from the model generator template.
push time in 2 days
pull request commentbalderdashy/sails-docs
[patch] Add example to generate model cli docs
As an aside: I'd suggest adding specific descriptions of these PR title tags to the contribution guidelines. It's not clear whether I should use [proposal], [patch], or [misc] for a documentation change like this.
comment created time in 2 days
PR opened balderdashy/sails-docs
It was not clear how generate model takes attributes arguments and it took me a while to find out how to do it. Hopefully this helps other users.
pr created time in 2 days
push eventbrianpeiris/sails-docs
commit sha 599c6c0dbe650b5bdfeb2de0256865ef61e59c42
Add example to generate model cli docs It was not clear how `generate model` takes attributes arguments and it took me a while to find out how to do it. Hopefully this helps other users.
push time in 2 days
The source markdown files for the official Sails.js documentation, which gets compiled, squeezed, and stretched into HTML when we deploy the Sails website. (Latest v1.x docs are now on master!)
https://sailsjs.com/documentation
fork in 2 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
+import React, { useState, useEffect, useContext, createContext, useCallback, Children, cloneElement } from "react";+import PropTypes from "prop-types";+import { mediaSort, getMediaType } from "../../utils/media-sorting.js";++function getDisplayString(el) {+ // Having a listed-media component does not guarantee the existence of a media-loader component,+ // so don't crash if there isn't one.+ const url = (el.components["media-loader"] && el.components["media-loader"].data.src) || "";+ const split = url.split("/");+ const resourceName = split[split.length - 1].split("?")[0];+ let httpIndex = -1;+ for (let i = 0; i < split.length; i++) {+ if (split[i].indexOf("http") !== -1) {+ httpIndex = i;+ }+ }++ let host = "";+ let lessHost = "";+ if (httpIndex !== -1 && split.length > httpIndex + 3) {+ host = split[httpIndex + 2];+ const hostSplit = host.split(".");+ if (hostSplit.length > 1) {+ lessHost = `${hostSplit[hostSplit.length - 2]}.${hostSplit[hostSplit.length - 1]}`;+ }+ }++ const firstPart =+ url.indexOf("poly.google") !== -1+ ? "Google Poly"+ : url.indexOf("sketchfab.com") !== -1+ ? "Sketchfab"+ : url.indexOf("youtube.com") !== -1+ ? "YouTube"+ : lessHost;++ return `${firstPart} ... ${resourceName.substr(0, 4)}`;+}++const ObjectListContext = createContext({+ objects: [],+ focusedObject: null,+ selectedObject: null,+ focusObject: () => {},+ unfocusObject: () => {},+ inspectObject: () => {},+ uninspectObject: () => {}+});++export function ObjectListProvider({ scene, children }) {+ const [objects, setObjects] = useState([]);+ const [focusedObject, setFocusedObject] = useState(null); // The object currently shown in the viewport+ const [selectedObject, setSelectedObject] = useState(null); // The object currently selected in the object list++ useEffect(+ () => {+ function updateMediaEntities() {+ const objects = scene.systems["listed-media"].els.sort(mediaSort).map(el => ({+ id: el.object3D.id,+ name: getDisplayString(el),+ type: getMediaType(el),+ el,+ enableLights: false
Ah, I get it now.
comment created time in 2 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
+import React from "react";+import PropTypes from "prop-types";+import { ObjectMenu, ObjectMenuButton } from "./ObjectMenu";+import { useObjectList } from "./useObjectList";+import { usePinObject, useRemoveObject, useGoToSelectedObject, getObjectUrl, getPlayerInfo } from "./object-hooks";+import { ReactComponent as PinIcon } from "../icons/Pin.svg";+import { ReactComponent as LinkIcon } from "../icons/Link.svg";+import { ReactComponent as GoToIcon } from "../icons/GoTo.svg";+import { ReactComponent as DeleteIcon } from "../icons/Delete.svg";+import { ReactComponent as AvatarIcon } from "../icons/Avatar.svg";++export function ObjectMenuContainer({ hubChannel, scene, onOpenProfile }) {+ const { objects, activeObject, deselectObject, selectNextObject, selectPrevObject } = useObjectList();+ const { canPin, isPinned, togglePinned } = usePinObject(hubChannel, scene, activeObject);+ const { canRemoveObject, removeObject } = useRemoveObject(hubChannel, scene, activeObject);+ const { canGoTo, goToSelectedObject } = useGoToSelectedObject(scene, activeObject);+ const url = getObjectUrl(activeObject);+ const isPlayer = getPlayerInfo(activeObject);++ return (+ <ObjectMenu+ title="Object"+ currentObjectIndex={objects.indexOf(activeObject) + 1}+ objectCount={objects.length}+ onClose={deselectObject}+ onBack={deselectObject}+ onNextObject={selectNextObject}+ onPrevObject={selectPrevObject}+ >+ {canPin && (+ <ObjectMenuButton onClick={togglePinned}>+ <PinIcon />+ <span>{isPinned ? "Unpin" : "Pin"}</span>+ </ObjectMenuButton>+ )}+ {url && (+ <ObjectMenuButton as="a" href={url} target="_blank" rel="noopener noreferrer">+ <LinkIcon />+ <span>Link</span>+ </ObjectMenuButton>+ )}+ {canGoTo && (+ <ObjectMenuButton+ onClick={() => {+ goToSelectedObject();+ deselectObject();+ }}+ >+ <GoToIcon />+ <span>View</span>+ </ObjectMenuButton>+ )}+ {canRemoveObject && (+ <ObjectMenuButton+ onClick={() => {+ removeObject();+ deselectObject();+ }}+ >+ <DeleteIcon />+ <span>Delete</span>+ </ObjectMenuButton>+ )}+ {isPlayer && (+ <ObjectMenuButton onClick={onOpenProfile}>+ <AvatarIcon />+ <span>Edit Avatar</span>+ </ObjectMenuButton>
I think you might be mistaken. It is possible to inspect other avatars at the moment, you just right-click on them. The best way is probably to add a isLocalPlayer function that uses the isLocalPlayerInfo property from the player-info component.
comment created time in 2 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
+import React, { useCallback, useRef } from "react";+import PropTypes from "prop-types";+import { ObjectsSidebar, ObjectsSidebarItem } from "./ObjectsSidebar";+import { List } from "../layout/List";+import { useObjectList } from "./useObjectList";++export function ObjectsSidebarContainer({ onClose }) {+ const listRef = useRef();+ const { objects, selectedObject, selectObject, unfocusObject, focusObject } = useObjectList();++ const onUnfocusListItem = useCallback(+ e => {+ if (e.relatedTarget === listRef.current || !listRef.current.contains(e.relatedTarget)) {+ unfocusObject();+ }+ },+ [unfocusObject, listRef]+ );++ return (+ <ObjectsSidebar objectCount={objects.length} onClose={onClose}>+ <List ref={listRef}>+ {objects.map(object => (+ <ObjectsSidebarItem+ selected={selectedObject === object}+ object={object}+ key={object.id}+ onClick={() => selectObject(object)}+ onMouseOver={() => focusObject(object)}+ onFocus={() => focusObject(object)}+ onMouseOut={onUnfocusListItem}+ onBlur={onUnfocusListItem}+ />+ ))}+ </List>+ </ObjectsSidebar>
Design nit: It would be nice if the design made it clear that the objects list is empty. I'm thinking something like a large centered message, maybe with iconography, that says "There are no objects in the room". Right now you're just presented with a blank sidebar except for the title and the close button and close button at the top. It's especially important on mobile, where the blank space of the sidebar takes up the entire screen.
comment created time in 5 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
+import { useEffect, useState, useCallback, useMemo } from "react";+import { removeNetworkedObject } from "../../utils/removeNetworkedObject";+import { rotateInPlaceAroundWorldUp, affixToWorldUp } from "../../utils/three-utils";+import { getPromotionTokenForFile } from "../../utils/media-utils";++function getPinnedState(el) {+ return el.components.pinnable && el.components.pinnable.data.pinned;+}++function hasIsStaticTag(el) {+ return el.components.tags && el.components.tags.data.isStatic;
return !!(el.components.tags && el.components.tags.data.isStatic);
comment created time in 5 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
+import { useEffect, useState, useCallback, useMemo } from "react";+import { removeNetworkedObject } from "../../utils/removeNetworkedObject";+import { rotateInPlaceAroundWorldUp, affixToWorldUp } from "../../utils/three-utils";+import { getPromotionTokenForFile } from "../../utils/media-utils";++function getPinnedState(el) {+ return el.components.pinnable && el.components.pinnable.data.pinned;+}++function hasIsStaticTag(el) {+ return el.components.tags && el.components.tags.data.isStatic;+}++export function getPlayerInfo(object) {+ return object.el.components["player-info"] && object.el.components["player-info"].data;+}
This is only used to determine if an object is a player. Maybe just call it isPlayer and have it strictly return a boolean.
comment created time in 5 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
+import { useEffect, useState, useCallback, useMemo } from "react";+import { removeNetworkedObject } from "../../utils/removeNetworkedObject";+import { rotateInPlaceAroundWorldUp, affixToWorldUp } from "../../utils/three-utils";+import { getPromotionTokenForFile } from "../../utils/media-utils";++function getPinnedState(el) {+ return el.components.pinnable && el.components.pinnable.data.pinned;
return !!(el.components.pinnable && el.components.pinnable.data.pinned);
comment created time in 5 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
+import React, { useState, useEffect, useContext, createContext, useCallback, Children, cloneElement } from "react";+import PropTypes from "prop-types";+import { mediaSort, getMediaType } from "../../utils/media-sorting.js";++function getDisplayString(el) {+ // Having a listed-media component does not guarantee the existence of a media-loader component,+ // so don't crash if there isn't one.+ const url = (el.components["media-loader"] && el.components["media-loader"].data.src) || "";+ const split = url.split("/");+ const resourceName = split[split.length - 1].split("?")[0];+ let httpIndex = -1;+ for (let i = 0; i < split.length; i++) {+ if (split[i].indexOf("http") !== -1) {+ httpIndex = i;+ }+ }++ let host = "";+ let lessHost = "";+ if (httpIndex !== -1 && split.length > httpIndex + 3) {+ host = split[httpIndex + 2];+ const hostSplit = host.split(".");+ if (hostSplit.length > 1) {+ lessHost = `${hostSplit[hostSplit.length - 2]}.${hostSplit[hostSplit.length - 1]}`;+ }+ }++ const firstPart =+ url.indexOf("poly.google") !== -1+ ? "Google Poly"+ : url.indexOf("sketchfab.com") !== -1+ ? "Sketchfab"+ : url.indexOf("youtube.com") !== -1+ ? "YouTube"+ : lessHost;++ return `${firstPart} ... ${resourceName.substr(0, 4)}`;+}++const ObjectListContext = createContext({+ objects: [],+ focusedObject: null,+ selectedObject: null,+ focusObject: () => {},+ unfocusObject: () => {},+ inspectObject: () => {},+ uninspectObject: () => {}+});++export function ObjectListProvider({ scene, children }) {+ const [objects, setObjects] = useState([]);+ const [focusedObject, setFocusedObject] = useState(null); // The object currently shown in the viewport+ const [selectedObject, setSelectedObject] = useState(null); // The object currently selected in the object list++ useEffect(+ () => {+ function updateMediaEntities() {+ const objects = scene.systems["listed-media"].els.sort(mediaSort).map(el => ({+ id: el.object3D.id,+ name: getDisplayString(el),+ type: getMediaType(el),+ el,+ enableLights: false+ }));++ setObjects(objects);+ }++ let timeout;++ function onListedMediaChanged() {+ // HACK: The listed-media component exists before the media-loader component does, in cases where an entity is created from a network template because of an incoming message, so don't updateMediaEntities right away.+ // Sorry in advance for the day this comment is out of date.+ timeout = setTimeout(() => updateMediaEntities(), 0);+ }++ scene.addEventListener("listed_media_changed", onListedMediaChanged);++ updateMediaEntities();++ return () => {+ scene.removeEventListener("listed_media_changed", updateMediaEntities);+ clearTimeout(timeout);+ };+ },+ [scene, setObjects]+ );++ useEffect(+ () => {+ function onInspectTargetChanged() {+ const cameraSystem = scene.systems["hubs-systems"].cameraSystem;++ const inspectedEl = cameraSystem.inspectable && cameraSystem.inspectable.el;++ if (inspectedEl) {+ setSelectedObject({+ id: inspectedEl.object3D.id,+ name: getDisplayString(inspectedEl),+ type: getMediaType(inspectedEl),+ el: inspectedEl,+ enableLights: true+ });+ } else {+ setSelectedObject(null);+ }+ }++ scene.addEventListener("inspect-target-changed", onInspectTargetChanged);++ return () => {+ scene.removeEventListener("inspect-target-changed", onInspectTargetChanged);+ };+ },+ [scene, setSelectedObject, objects, selectedObject]+ );++ const selectObject = useCallback(+ object => {+ const cameraSystem = scene.systems["hubs-systems"].cameraSystem;++ setSelectedObject(object);++ if (object.el.object3D !== cameraSystem.inspectable) {+ if (cameraSystem.inspectable) {+ cameraSystem.uninspect(false);+ }++ cameraSystem.enableLights = object.enableLights;+ cameraSystem.inspect(object.el, 1.5, true, false);+ }+ },+ [scene, setSelectedObject]+ );++ const deselectObject = useCallback(+ () => {+ const cameraSystem = scene.systems["hubs-systems"].cameraSystem;++ setSelectedObject(null);++ cameraSystem.enableLights = true;+ cameraSystem.uninspect(false);++ if (focusedObject) {+ cameraSystem.enableLights = focusedObject.enableLights;+ cameraSystem.inspect(focusedObject.el, 1.5, true, false);+ }+ },+ [scene, setSelectedObject, focusedObject]+ );++ const focusObject = useCallback(+ object => {+ const cameraSystem = scene.systems["hubs-systems"].cameraSystem;++ setFocusedObject(object);++ if (object.el.object3D !== cameraSystem.inspectable) {+ if (cameraSystem.inspectable) {+ cameraSystem.uninspect(false);+ }++ cameraSystem.enableLights = object.enableLights;+ cameraSystem.inspect(object.el, 1.5, true, false);+ }+ },+ [scene, setFocusedObject]+ );++ const unfocusObject = useCallback(+ () => {+ const cameraSystem = scene.systems["hubs-systems"].cameraSystem;++ setFocusedObject(null);++ cameraSystem.enableLights = true;+ cameraSystem.uninspect(false);++ if (selectedObject) {+ cameraSystem.enableLights = selectedObject.enableLights;+ cameraSystem.inspect(selectedObject.el, 1.5, true, false);+ }+ },+ [scene, setFocusedObject, selectedObject]+ );++ const selectNextObject = useCallback(+ () => {+ const curObjIdx = objects.indexOf(selectedObject);++ if (curObjIdx !== -1) {+ const nextObjIdx = (curObjIdx + 1) % objects.length;+ selectObject(objects[nextObjIdx]);+ }+ },+ [selectObject, objects, selectedObject]+ );++ const selectPrevObject = useCallback(+ () => {+ const curObjIdx = objects.indexOf(selectedObject);++ if (curObjIdx !== -1) {+ const nextObjIdx = curObjIdx === 0 ? objects.length - 1 : curObjIdx - 1;+ selectObject(objects[nextObjIdx]);+ }+ },+ [selectObject, objects, selectedObject]+ );++ const context = {+ objects,+ activeObject: focusedObject || selectedObject,+ focusedObject,+ selectedObject,+ focusObject,+ unfocusObject,+ selectObject,+ deselectObject,+ selectPrevObject,+ selectNextObject+ };++ // Note: If we move ui-root to a functional component and use hooks,+ // we can use the useObjectList hook instead of cloneElement.
Should this remain in the code, or is it a personal TODO for later?
comment created time in 5 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
+import React, { useState, useEffect, useContext, createContext, useCallback, Children, cloneElement } from "react";+import PropTypes from "prop-types";+import { mediaSort, getMediaType } from "../../utils/media-sorting.js";++function getDisplayString(el) {+ // Having a listed-media component does not guarantee the existence of a media-loader component,+ // so don't crash if there isn't one.+ const url = (el.components["media-loader"] && el.components["media-loader"].data.src) || "";+ const split = url.split("/");+ const resourceName = split[split.length - 1].split("?")[0];+ let httpIndex = -1;+ for (let i = 0; i < split.length; i++) {+ if (split[i].indexOf("http") !== -1) {+ httpIndex = i;+ }+ }++ let host = "";+ let lessHost = "";+ if (httpIndex !== -1 && split.length > httpIndex + 3) {+ host = split[httpIndex + 2];+ const hostSplit = host.split(".");+ if (hostSplit.length > 1) {+ lessHost = `${hostSplit[hostSplit.length - 2]}.${hostSplit[hostSplit.length - 1]}`;+ }+ }++ const firstPart =+ url.indexOf("poly.google") !== -1+ ? "Google Poly"+ : url.indexOf("sketchfab.com") !== -1+ ? "Sketchfab"+ : url.indexOf("youtube.com") !== -1+ ? "YouTube"+ : lessHost;++ return `${firstPart} ... ${resourceName.substr(0, 4)}`;+}++const ObjectListContext = createContext({+ objects: [],+ focusedObject: null,+ selectedObject: null,+ focusObject: () => {},+ unfocusObject: () => {},+ inspectObject: () => {},+ uninspectObject: () => {}+});++export function ObjectListProvider({ scene, children }) {+ const [objects, setObjects] = useState([]);+ const [focusedObject, setFocusedObject] = useState(null); // The object currently shown in the viewport+ const [selectedObject, setSelectedObject] = useState(null); // The object currently selected in the object list++ useEffect(+ () => {+ function updateMediaEntities() {+ const objects = scene.systems["listed-media"].els.sort(mediaSort).map(el => ({+ id: el.object3D.id,+ name: getDisplayString(el),+ type: getMediaType(el),+ el,+ enableLights: false+ }));++ setObjects(objects);+ }++ let timeout;++ function onListedMediaChanged() {+ // HACK: The listed-media component exists before the media-loader component does, in cases where an entity is created from a network template because of an incoming message, so don't updateMediaEntities right away.+ // Sorry in advance for the day this comment is out of date.+ timeout = setTimeout(() => updateMediaEntities(), 0);+ }++ scene.addEventListener("listed_media_changed", onListedMediaChanged);++ updateMediaEntities();++ return () => {+ scene.removeEventListener("listed_media_changed", updateMediaEntities);+ clearTimeout(timeout);+ };+ },+ [scene, setObjects]+ );++ useEffect(+ () => {+ function onInspectTargetChanged() {+ const cameraSystem = scene.systems["hubs-systems"].cameraSystem;++ const inspectedEl = cameraSystem.inspectable && cameraSystem.inspectable.el;++ if (inspectedEl) {+ setSelectedObject({+ id: inspectedEl.object3D.id,+ name: getDisplayString(inspectedEl),+ type: getMediaType(inspectedEl),+ el: inspectedEl,+ enableLights: true+ });+ } else {+ setSelectedObject(null);+ }+ }++ scene.addEventListener("inspect-target-changed", onInspectTargetChanged);++ return () => {+ scene.removeEventListener("inspect-target-changed", onInspectTargetChanged);+ };+ },+ [scene, setSelectedObject, objects, selectedObject]+ );++ const selectObject = useCallback(+ object => {+ const cameraSystem = scene.systems["hubs-systems"].cameraSystem;++ setSelectedObject(object);++ if (object.el.object3D !== cameraSystem.inspectable) {+ if (cameraSystem.inspectable) {+ cameraSystem.uninspect(false);+ }++ cameraSystem.enableLights = object.enableLights;+ cameraSystem.inspect(object.el, 1.5, true, false);+ }+ },+ [scene, setSelectedObject]+ );++ const deselectObject = useCallback(+ () => {+ const cameraSystem = scene.systems["hubs-systems"].cameraSystem;++ setSelectedObject(null);++ cameraSystem.enableLights = true;+ cameraSystem.uninspect(false);++ if (focusedObject) {+ cameraSystem.enableLights = focusedObject.enableLights;+ cameraSystem.inspect(focusedObject.el, 1.5, true, false);+ }+ },+ [scene, setSelectedObject, focusedObject]+ );++ const focusObject = useCallback(+ object => {+ const cameraSystem = scene.systems["hubs-systems"].cameraSystem;++ setFocusedObject(object);++ if (object.el.object3D !== cameraSystem.inspectable) {+ if (cameraSystem.inspectable) {+ cameraSystem.uninspect(false);+ }++ cameraSystem.enableLights = object.enableLights;+ cameraSystem.inspect(object.el, 1.5, true, false);+ }+ },+ [scene, setFocusedObject]+ );++ const unfocusObject = useCallback(+ () => {+ const cameraSystem = scene.systems["hubs-systems"].cameraSystem;++ setFocusedObject(null);++ cameraSystem.enableLights = true;+ cameraSystem.uninspect(false);++ if (selectedObject) {+ cameraSystem.enableLights = selectedObject.enableLights;+ cameraSystem.inspect(selectedObject.el, 1.5, true, false);+ }+ },+ [scene, setFocusedObject, selectedObject]+ );
It's a bit unfortunate that selectObject/deleselectObject and focusObject/unfocusObject are almost, but not quite, identical. If there is a way to refactor and reuse the code, it would be nice, since I can imagine we might introduce bugs later by accidentally interacting with the cameraSystem one way in one of the pairs, and not in the other.
comment created time in 5 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
+import React, { useState, useEffect, useContext, createContext, useCallback, Children, cloneElement } from "react";+import PropTypes from "prop-types";+import { mediaSort, getMediaType } from "../../utils/media-sorting.js";++function getDisplayString(el) {+ // Having a listed-media component does not guarantee the existence of a media-loader component,+ // so don't crash if there isn't one.+ const url = (el.components["media-loader"] && el.components["media-loader"].data.src) || "";+ const split = url.split("/");+ const resourceName = split[split.length - 1].split("?")[0];+ let httpIndex = -1;+ for (let i = 0; i < split.length; i++) {+ if (split[i].indexOf("http") !== -1) {+ httpIndex = i;+ }+ }++ let host = "";+ let lessHost = "";+ if (httpIndex !== -1 && split.length > httpIndex + 3) {+ host = split[httpIndex + 2];+ const hostSplit = host.split(".");+ if (hostSplit.length > 1) {+ lessHost = `${hostSplit[hostSplit.length - 2]}.${hostSplit[hostSplit.length - 1]}`;+ }+ }++ const firstPart =+ url.indexOf("poly.google") !== -1+ ? "Google Poly"+ : url.indexOf("sketchfab.com") !== -1+ ? "Sketchfab"+ : url.indexOf("youtube.com") !== -1+ ? "YouTube"+ : lessHost;++ return `${firstPart} ... ${resourceName.substr(0, 4)}`;+}++const ObjectListContext = createContext({+ objects: [],+ focusedObject: null,+ selectedObject: null,+ focusObject: () => {},+ unfocusObject: () => {},+ inspectObject: () => {},+ uninspectObject: () => {}+});++export function ObjectListProvider({ scene, children }) {+ const [objects, setObjects] = useState([]);+ const [focusedObject, setFocusedObject] = useState(null); // The object currently shown in the viewport+ const [selectedObject, setSelectedObject] = useState(null); // The object currently selected in the object list++ useEffect(+ () => {+ function updateMediaEntities() {+ const objects = scene.systems["listed-media"].els.sort(mediaSort).map(el => ({+ id: el.object3D.id,+ name: getDisplayString(el),+ type: getMediaType(el),+ el,+ enableLights: false
As far as I can tell, none of the codepaths change this to true. Previously, there was UI to toggle lights, which would set the "show-background-while-inspecting" flag in local storage, but this PR removes that as well.
In other words, there is no mechanism for a user to enable lights while inspecting an object through the object list. If it's not an omission in the UX, maybe we should remove this state from the objects array, and remove references to the local storage flag as well.
comment created time in 5 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
It's a little surprising that these svg files are under /react-components/, I would have expected them to be under assets. Maybe worth changing? Unless there's a good reason they're here that I'm not aware of.
comment created time in 5 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
class UIRoot extends Component { }, 0); }); }++ if (!this.props.selectedObject || !prevProps.selectedObject) {
Took me a while to realize that selectedObject was implicitly coming from ObjectListProvider. Out of curiosity, do you have a technique to trace props back to their source, or do you just use the React Dev Tools at runtime to figure it out?
comment created time in 5 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
class UIRoot extends Component { pushHistoryState = (k, v) => pushHistoryState(this.props.history, k, v); + setSidebar(sidebarId, otherState) {+ const sceneEl = this.props.scene;++ if (sidebarId) {+ sceneEl.classList.add(roomLayoutStyles.sidebarOpen);+ } else {+ sceneEl.classList.remove(roomLayoutStyles.sidebarOpen);+ }++ sceneEl.renderer.setSize(sceneEl.clientWidth, sceneEl.clientHeight, false);+ sceneEl.camera.aspect = sceneEl.clientWidth / sceneEl.clientHeight;+ sceneEl.camera.updateProjectionMatrix();++ this.setState({ sidebarId, selectedUserId: null, ...otherState });+ }++ toggleSidebar(sidebarId, otherState) {+ const sceneEl = this.props.scene;++ this.setState(({ sidebarId: curSidebarId }) => {+ const nextSidebarId = curSidebarId === sidebarId ? null : sidebarId;++ if (nextSidebarId) {+ sceneEl.classList.add(roomLayoutStyles.sidebarOpen);+ } else {+ sceneEl.classList.remove(roomLayoutStyles.sidebarOpen);+ }++ sceneEl.renderer.setSize(sceneEl.clientWidth, sceneEl.clientHeight, false);+ sceneEl.camera.aspect = sceneEl.clientWidth / sceneEl.clientHeight;+ sceneEl.camera.updateProjectionMatrix();
Might be worth refactoring this classList style toggle and scene resize code since we do it three separate times in this file.
comment created time in 5 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
+import React from "react";+import PropTypes from "prop-types";+import { ObjectMenu, ObjectMenuButton } from "./ObjectMenu";+import { useObjectList } from "./useObjectList";+import { usePinObject, useRemoveObject, useGoToSelectedObject, getObjectUrl, getPlayerInfo } from "./object-hooks";+import { ReactComponent as PinIcon } from "../icons/Pin.svg";+import { ReactComponent as LinkIcon } from "../icons/Link.svg";+import { ReactComponent as GoToIcon } from "../icons/GoTo.svg";+import { ReactComponent as DeleteIcon } from "../icons/Delete.svg";+import { ReactComponent as AvatarIcon } from "../icons/Avatar.svg";++export function ObjectMenuContainer({ hubChannel, scene, onOpenProfile }) {+ const { objects, activeObject, deselectObject, selectNextObject, selectPrevObject } = useObjectList();+ const { canPin, isPinned, togglePinned } = usePinObject(hubChannel, scene, activeObject);+ const { canRemoveObject, removeObject } = useRemoveObject(hubChannel, scene, activeObject);+ const { canGoTo, goToSelectedObject } = useGoToSelectedObject(scene, activeObject);+ const url = getObjectUrl(activeObject);+ const isPlayer = getPlayerInfo(activeObject);++ return (+ <ObjectMenu+ title="Object"+ currentObjectIndex={objects.indexOf(activeObject) + 1}+ objectCount={objects.length}+ onClose={deselectObject}+ onBack={deselectObject}+ onNextObject={selectNextObject}+ onPrevObject={selectPrevObject}+ >+ {canPin && (+ <ObjectMenuButton onClick={togglePinned}>+ <PinIcon />+ <span>{isPinned ? "Unpin" : "Pin"}</span>+ </ObjectMenuButton>+ )}+ {url && (+ <ObjectMenuButton as="a" href={url} target="_blank" rel="noopener noreferrer">+ <LinkIcon />+ <span>Link</span>+ </ObjectMenuButton>+ )}+ {canGoTo && (+ <ObjectMenuButton+ onClick={() => {+ goToSelectedObject();+ deselectObject();+ }}+ >+ <GoToIcon />+ <span>View</span>+ </ObjectMenuButton>+ )}+ {canRemoveObject && (
More of a design critique, but I find it a bit annoying that buttons disappear after an interaction. When you Pin an object, the Delete button disappears. That resizes the menu, which means you need to now move your mouse again to Unpin. IMO, would be nice if the Delete button just switched to a disabled state.
comment created time in 5 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
+import React from "react";+import PropTypes from "prop-types";+import { ObjectMenu, ObjectMenuButton } from "./ObjectMenu";+import { useObjectList } from "./useObjectList";+import { usePinObject, useRemoveObject, useGoToSelectedObject, getObjectUrl, getPlayerInfo } from "./object-hooks";+import { ReactComponent as PinIcon } from "../icons/Pin.svg";+import { ReactComponent as LinkIcon } from "../icons/Link.svg";+import { ReactComponent as GoToIcon } from "../icons/GoTo.svg";+import { ReactComponent as DeleteIcon } from "../icons/Delete.svg";+import { ReactComponent as AvatarIcon } from "../icons/Avatar.svg";++export function ObjectMenuContainer({ hubChannel, scene, onOpenProfile }) {+ const { objects, activeObject, deselectObject, selectNextObject, selectPrevObject } = useObjectList();+ const { canPin, isPinned, togglePinned } = usePinObject(hubChannel, scene, activeObject);+ const { canRemoveObject, removeObject } = useRemoveObject(hubChannel, scene, activeObject);+ const { canGoTo, goToSelectedObject } = useGoToSelectedObject(scene, activeObject);+ const url = getObjectUrl(activeObject);+ const isPlayer = getPlayerInfo(activeObject);++ return (+ <ObjectMenu+ title="Object"+ currentObjectIndex={objects.indexOf(activeObject) + 1}+ objectCount={objects.length}+ onClose={deselectObject}+ onBack={deselectObject}+ onNextObject={selectNextObject}+ onPrevObject={selectPrevObject}+ >+ {canPin && (+ <ObjectMenuButton onClick={togglePinned}>+ <PinIcon />+ <span>{isPinned ? "Unpin" : "Pin"}</span>+ </ObjectMenuButton>+ )}+ {url && (+ <ObjectMenuButton as="a" href={url} target="_blank" rel="noopener noreferrer">+ <LinkIcon />+ <span>Link</span>
Are you intentionally skipping i18n for new strings in this PR? If not, would be nice to add and use new strings while you're at it. I spotted "Link", "View", "Delete", "Edit Avatar", "Object" on the ObjectMenu title, and "Objects" on the ObjectsSidebar title.
comment created time in 5 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
+import React from "react";+import PropTypes from "prop-types";+import { ObjectMenu, ObjectMenuButton } from "./ObjectMenu";+import { useObjectList } from "./useObjectList";+import { usePinObject, useRemoveObject, useGoToSelectedObject, getObjectUrl, getPlayerInfo } from "./object-hooks";+import { ReactComponent as PinIcon } from "../icons/Pin.svg";+import { ReactComponent as LinkIcon } from "../icons/Link.svg";+import { ReactComponent as GoToIcon } from "../icons/GoTo.svg";+import { ReactComponent as DeleteIcon } from "../icons/Delete.svg";+import { ReactComponent as AvatarIcon } from "../icons/Avatar.svg";++export function ObjectMenuContainer({ hubChannel, scene, onOpenProfile }) {+ const { objects, activeObject, deselectObject, selectNextObject, selectPrevObject } = useObjectList();+ const { canPin, isPinned, togglePinned } = usePinObject(hubChannel, scene, activeObject);+ const { canRemoveObject, removeObject } = useRemoveObject(hubChannel, scene, activeObject);+ const { canGoTo, goToSelectedObject } = useGoToSelectedObject(scene, activeObject);+ const url = getObjectUrl(activeObject);+ const isPlayer = getPlayerInfo(activeObject);++ return (+ <ObjectMenu+ title="Object"+ currentObjectIndex={objects.indexOf(activeObject) + 1}+ objectCount={objects.length}+ onClose={deselectObject}+ onBack={deselectObject}+ onNextObject={selectNextObject}+ onPrevObject={selectPrevObject}+ >+ {canPin && (+ <ObjectMenuButton onClick={togglePinned}>+ <PinIcon />+ <span>{isPinned ? "Unpin" : "Pin"}</span>+ </ObjectMenuButton>+ )}+ {url && (+ <ObjectMenuButton as="a" href={url} target="_blank" rel="noopener noreferrer">+ <LinkIcon />+ <span>Link</span>+ </ObjectMenuButton>+ )}+ {canGoTo && (+ <ObjectMenuButton+ onClick={() => {+ goToSelectedObject();+ deselectObject();+ }}+ >+ <GoToIcon />+ <span>View</span>+ </ObjectMenuButton>+ )}+ {canRemoveObject && (+ <ObjectMenuButton+ onClick={() => {+ removeObject();+ deselectObject();+ }}+ >+ <DeleteIcon />+ <span>Delete</span>+ </ObjectMenuButton>+ )}+ {isPlayer && (+ <ObjectMenuButton onClick={onOpenProfile}>+ <AvatarIcon />+ <span>Edit Avatar</span>+ </ObjectMenuButton>
Perhaps we should only show this "Edit Avatar" button when you are inspecting your own avatar? Doesn't seem to make sense to show it when you're inspecting someone else's avatar. A "Use as My Avatar" button would be neat though, if we want to allow that when you're inspecting someone else's avatar.
comment created time in 5 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
+import React from "react";+import PropTypes from "prop-types";+import classNames from "classnames";+import styles from "./ObjectsSidebar.scss";+import { Sidebar, CloseButton } from "../sidebar/Sidebar";+import { ButtonListItem } from "../layout/List";+import listStyles from "../layout/List.scss";+import { ReactComponent as ObjectIcon } from "../icons/Object.svg";+import { ReactComponent as ImageIcon } from "../icons/Image.svg";+import { ReactComponent as VideoIcon } from "../icons/Video.svg";+import { ReactComponent as AudioIcon } from "../icons/Audio.svg";+import { ReactComponent as TextDocumentIcon } from "../icons/TextDocument.svg";++function getObjectIcon(type) {+ switch (type) {+ case "video":+ return VideoIcon;+ case "audio":+ return AudioIcon;+ case "image":+ return ImageIcon;+ case "pdf":+ return TextDocumentIcon;+ case "model":+ default:+ return ObjectIcon;+ }+}++const objectTypeNames = {+ video: "Video",+ audio: "Audio",+ image: "Image",+ pdf: "PDF",+ model: "Model",+ default: "Object"
Looks like these were never internationalized, but would be nice to add i18n now.
comment created time in 5 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
+import React from "react";+import PropTypes from "prop-types";+import { ObjectMenu, ObjectMenuButton } from "./ObjectMenu";+import { useObjectList } from "./useObjectList";+import { usePinObject, useRemoveObject, useGoToSelectedObject, getObjectUrl, getPlayerInfo } from "./object-hooks";+import { ReactComponent as PinIcon } from "../icons/Pin.svg";+import { ReactComponent as LinkIcon } from "../icons/Link.svg";+import { ReactComponent as GoToIcon } from "../icons/GoTo.svg";+import { ReactComponent as DeleteIcon } from "../icons/Delete.svg";+import { ReactComponent as AvatarIcon } from "../icons/Avatar.svg";++export function ObjectMenuContainer({ hubChannel, scene, onOpenProfile }) {+ const { objects, activeObject, deselectObject, selectNextObject, selectPrevObject } = useObjectList();+ const { canPin, isPinned, togglePinned } = usePinObject(hubChannel, scene, activeObject);+ const { canRemoveObject, removeObject } = useRemoveObject(hubChannel, scene, activeObject);+ const { canGoTo, goToSelectedObject } = useGoToSelectedObject(scene, activeObject);+ const url = getObjectUrl(activeObject);+ const isPlayer = getPlayerInfo(activeObject);++ return (+ <ObjectMenu+ title="Object"+ currentObjectIndex={objects.indexOf(activeObject) + 1}+ objectCount={objects.length}+ onClose={deselectObject}+ onBack={deselectObject}+ onNextObject={selectNextObject}+ onPrevObject={selectPrevObject}+ >+ {canPin && (+ <ObjectMenuButton onClick={togglePinned}>+ <PinIcon />+ <span>{isPinned ? "Unpin" : "Pin"}</span>
"Pin" and "Unpin" do already have i18n strings ("object-info.pin-button" and "object-info.unpin-button"), so maybe just use them here?
comment created time in 5 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
import styles from "./IconButton.scss"; import textInputStyles from "./TextInput.scss"; export const IconButton = memo(- forwardRef(({ className, as: ButtonComponent, children, ...rest }, ref) => {+ forwardRef(({ className, as: ButtonComponent, compactSm, children, ...rest }, ref) => { return ( <ButtonComponent- className={classNames(styles.iconButton, textInputStyles.iconButton, className)}+ className={classNames(+ styles.iconButton,+ textInputStyles.iconButton,+ { [styles.compactSm]: compactSm },
nit: Could we just call this compactSmall, or a better name?
comment created time in 8 days
Pull request review commentmozilla/hubs
Room UI Redesign: Object List and Object Menu
+import React from "react";+import PropTypes from "prop-types";+import { ObjectMenu, ObjectMenuButton } from "./ObjectMenu";+import { useObjectList } from "./useObjectList";+import { usePinObject, useRemoveObject, useGoToSelectedObject, getObjectUrl, getPlayerInfo } from "./object-hooks";+import { ReactComponent as PinIcon } from "../icons/Pin.svg";+import { ReactComponent as LinkIcon } from "../icons/Link.svg";+import { ReactComponent as GoToIcon } from "../icons/GoTo.svg";+import { ReactComponent as DeleteIcon } from "../icons/Delete.svg";+import { ReactComponent as AvatarIcon } from "../icons/Avatar.svg";++export function ObjectMenuContainer({ hubChannel, scene, onOpenProfile }) {+ const { objects, activeObject, deselectObject, selectNextObject, selectPrevObject } = useObjectList();+ const { canPin, isPinned, togglePinned } = usePinObject(hubChannel, scene, activeObject);+ const { canRemoveObject, removeObject } = useRemoveObject(hubChannel, scene, activeObject);+ const { canGoTo, goToSelectedObject } = useGoToSelectedObject(scene, activeObject);+ const url = getObjectUrl(activeObject);+ const isPlayer = getPlayerInfo(activeObject);++ return (+ <ObjectMenu+ title="Object"+ currentObjectIndex={objects.indexOf(activeObject) + 1}
Seems like the + 1 should be a render concern inside the ObjectMenu component, and currentObjectIndex should just represent the actual array index of the current object.
comment created time in 5 days
push eventmozilla/hubs
commit sha 0adc5b6e5013d2242d0f84fb5c7ccce0c107277a
Fix safari by avoiding flexbox
commit sha c9653722d4d25d31b139aac60ebe199c3d5eb12a
Merge pull request #3216 from mozilla/bug/landing-safari Fix landing page in safari by avoiding flexbox
push time in 6 days
push eventmozilla/hubs
commit sha 526bc1bfc125cf65c0525f35ff865579277c32be
improve some Japanese translations
commit sha 2f7aa2eee8b3e8b2b9a522c1668ad6b3b009b906
fix percent symbols in the Japanese locale fie
commit sha 7837bc77f6dd9ca1e9ffef6892c3c9fd5ed96765
Japanese translation: unify translations of "phone"
commit sha aa1b074ce6402984bddb67f0ffd29f36dc1eb862
Merge pull request #3124 from kn1cht/fix-japanese-locale Fix flaws in Japanese translations
push time in 6 days
PR merged mozilla/hubs
I fixed some issues in the Japanese translations (added in #3102 ).
1. Variables in ja.json is not replaced correctly
There are some variables escaped with "%...%" in the translation files. https://github.com/mozilla/hubs/blob/92000b28a659037fd30c12fd82424d1d763bb618/src/assets/locales/jp.json#L11-L12
I noticed that these variables are not replaced in the Japanese environment. <img src="https://user-images.githubusercontent.com/16277200/95012394-18ae1680-0673-11eb-8e86-60010d00b073.png" width=250><img src="https://user-images.githubusercontent.com/16277200/95012406-35e2e500-0673-11eb-91a7-ef8da8be0802.png" width=300>
The cause of this issue is that the percent character in ja.json is "% (U+FF05)".
U+FF05 is the Fullwidth (全角) percent sign which is used in east asian languages. This is a different character to the basic percent sign (%, U+0025).
Thus replacing U+FF05 with U+0025 in ja.json solves this issue.
2. Improve some sentences & words
As a native Japanese speaker, I fixed some parts of the current translations which are difficult to understand as Japanese text or not translated yet. For these parts, it would be helpful if other Japanese speakers review them (maybe @takahirox , @kaitas ? ).
| en | ja (before the changes) | ja (after the changes) |
|---|---|---|
| No email? You may not be able to create an account. | メールがありませんか?アカウントを作成できます。」 | メールアドレスをお持ちでない方は,アカウントを作成できません。 |
| You are now signed in. | サインインが完了しました/サインインできました/ログインしました | サインインしました |
| Pin Objects | ピンオブジェクト | オブジェクトをピン |
| Yes, Promote | はい,プロモート | はい,昇格させます |
| Enter Room | Enter Room | ルームに入る |
| Leave Room | Leave Room | ルームを退出 |
| Enter on Screen / Phone / ... | Enter on 画面 / 電話 / ... | デスクトップで入室 / 携帯電話で入室 / ... |
| Enter on Standalone VR | スタンドアロンVRで入力 | スタンドアロンVRで入室 |
| Phone or PC | 電話またはPC | 携帯電話またはPC |
| Find more custom avatar resources here | カスタムアバターリソースをもっと探す ここ | カスタムアバターの追加情報は こちら |
| Avatar GLB URL | アバターGLBURL | アバターGLBファイルのURL |
| Enter Now | Enter Now | 入室する |
| Hubs Cloud | ハブクラウド | Hubs Cloud |
| Add the %app-name% Bot to Discord | 追加する %app-name% Bot 不和に | Discordに %app-name% Bot を追加する |
| Go to Room Settings to lock down permissions for this room. | ルーム設定に移動して,このルームの権限をロックダウンしてください。 | ルーム設定に移動して,このルームの権限を制限してください。 |
| Controls | コントロール | 操作 / 操作方法 |
| Material quality | 材料品質 | マテリアル品質 |
| hubs instances | ハブインスタンス | Hubsインスタンス |
| Close Room ... | Close Room ... | 部屋を削除する ... |
pr closed time in 6 days
pull request commentmozilla/hubs
Fix flaws in Japanese translations
I can merge this now. Thanks for the fixes an improvements!
comment created time in 6 days
pull request commentmozilla/hubs
Bump http-proxy from 1.17.0 to 1.18.1
This seems like a big changeset, despite the minor version bump. We'll want to see which of our dependencies and codepaths actually use http-proxy and test accordingly.
comment created time in 6 days
pull request commentmozilla/hubs
Bump puppeteer from 1.3.0 to 1.13.0 in /scripts/bot
We should merge this, but it ought to be manually tested to make sure the bots don't break.
comment created time in 6 days
push eventmozilla/hubs
commit sha d301eb6d3a07963549b93ca04da5f684e653e002
Bump lodash.merge from 4.6.1 to 4.6.2 Bumps [lodash.merge](https://github.com/lodash/lodash) from 4.6.1 to 4.6.2. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/commits) Signed-off-by: dependabot[bot] <[email protected]>
commit sha 8cb6fa31cf62e37ad1f40037193f160669ef1fb0
Merge pull request #2975 from mozilla/dependabot/npm_and_yarn/lodash.merge-4.6.2 Bump lodash.merge from 4.6.1 to 4.6.2
push time in 6 days
delete branch mozilla/hubs
delete branch : dependabot/npm_and_yarn/lodash.merge-4.6.2
delete time in 6 days
PR merged mozilla/hubs
Bumps lodash.merge from 4.6.1 to 4.6.2. <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/lodash/lodash/commits">compare view</a></li> </ul> </details> <br />
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.
<details> <summary>Dependabot commands and options</summary> <br />
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot mergewill merge this PR after your CI passes on it@dependabot squash and mergewill squash and merge this PR after your CI passes on it@dependabot cancel mergewill cancel a previously requested merge and block automerging@dependabot reopenwill reopen this PR if it is closed@dependabot closewill close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)@dependabot use these labelswill set the current labels as the default for future PRs for this repo and language@dependabot use these reviewerswill set the current reviewers as the default for future PRs for this repo and language@dependabot use these assigneeswill set the current assignees as the default for future PRs for this repo and language@dependabot use this milestonewill set the current milestone as the default for future PRs for this repo and language
You can disable automated security fix PRs for this repo from the Security Alerts page.
</details>
pr closed time in 6 days
push eventmozilla/hubs
commit sha 9f24a4fb36e5768b1e7c36c3c1ddb7f4651eb6ff
Bump node-fetch from 2.6.0 to 2.6.1 Bumps [node-fetch](https://github.com/bitinn/node-fetch) from 2.6.0 to 2.6.1. - [Release notes](https://github.com/bitinn/node-fetch/releases) - [Changelog](https://github.com/node-fetch/node-fetch/blob/master/docs/CHANGELOG.md) - [Commits](https://github.com/bitinn/node-fetch/compare/v2.6.0...v2.6.1) Signed-off-by: dependabot[bot] <[email protected]>
commit sha 5a94b3bd44b88771d957001e1b60cda0be8e976c
Merge pull request #3010 from mozilla/dependabot/npm_and_yarn/node-fetch-2.6.1 Bump node-fetch from 2.6.0 to 2.6.1
push time in 6 days
delete branch mozilla/hubs
delete branch : dependabot/npm_and_yarn/node-fetch-2.6.1
delete time in 6 days
PR merged mozilla/hubs
Bumps node-fetch from 2.6.0 to 2.6.1. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/bitinn/node-fetch/releases">node-fetch's releases</a>.</em></p> <blockquote> <h2>v2.6.1</h2> <p><strong>This is an important security release. It is strongly recommended to update as soon as possible.</strong></p> <p>See <a href="https://github.com/node-fetch/node-fetch/blob/master/docs/CHANGELOG.md#v261">CHANGELOG</a> for details.</p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/node-fetch/node-fetch/blob/master/docs/CHANGELOG.md">node-fetch's changelog</a>.</em></p> <blockquote> <h2>v2.6.1</h2> <p><strong>This is an important security release. It is strongly recommended to update as soon as possible.</strong></p> <ul> <li>Fix: honor the <code>size</code> option after following a redirect.</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/node-fetch/node-fetch/commit/b5e2e41b2b50bf2997720d6125accaf0dd68c0ab"><code>b5e2e41</code></a> update version number</li> <li><a href="https://github.com/node-fetch/node-fetch/commit/2358a6c2563d1730a0cdaccc197c611949f6a334"><code>2358a6c</code></a> Honor the <code>size</code> option after following a redirect and revert data uri support</li> <li><a href="https://github.com/node-fetch/node-fetch/commit/8c197f8982a238b3c345c64b17bfa92e16b4f7c4"><code>8c197f8</code></a> docs: Fix typos and grammatical errors in README.md (<a href="https://github-redirect.dependabot.com/bitinn/node-fetch/issues/686">#686</a>)</li> <li><a href="https://github.com/node-fetch/node-fetch/commit/1e99050f944ac435fce26a9549eadcc2419a968a"><code>1e99050</code></a> fix: Change error message thrown with redirect mode set to error (<a href="https://github-redirect.dependabot.com/bitinn/node-fetch/issues/653">#653</a>)</li> <li><a href="https://github.com/node-fetch/node-fetch/commit/244e6f63d42025465796e3ca4ce813bf2c31fc5b"><code>244e6f6</code></a> docs: Show backers in README</li> <li><a href="https://github.com/node-fetch/node-fetch/commit/6a5d192034a0f438551dffb6d2d8df2c00921d16"><code>6a5d192</code></a> fix: Properly parse meta tag when parameters are reversed (<a href="https://github-redirect.dependabot.com/bitinn/node-fetch/issues/682">#682</a>)</li> <li><a href="https://github.com/node-fetch/node-fetch/commit/47a24a03eb49a49d81b768892aee10074ed54a91"><code>47a24a0</code></a> chore: Add opencollective badge</li> <li><a href="https://github.com/node-fetch/node-fetch/commit/7b136627c537cb24430b0310638c9177a85acee1"><code>7b13662</code></a> chore: Add funding link</li> <li><a href="https://github.com/node-fetch/node-fetch/commit/5535c2ed478d418969ecfd60c16453462de2a53f"><code>5535c2e</code></a> fix: Check for global.fetch before binding it (<a href="https://github-redirect.dependabot.com/bitinn/node-fetch/issues/674">#674</a>)</li> <li><a href="https://github.com/node-fetch/node-fetch/commit/1d5778ad0d910dbd1584fb407a186f5a0bc1ea22"><code>1d5778a</code></a> docs: Add Discord badge</li> <li>Additional commits viewable in <a href="https://github.com/bitinn/node-fetch/compare/v2.6.0...v2.6.1">compare view</a></li> </ul> </details> <details> <summary>Maintainer changes</summary> <p>This version was pushed to npm by <a href="https://www.npmjs.com/~akepinski">akepinski</a>, a new releaser for node-fetch since your current version.</p> </details> <br />
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.
<details> <summary>Dependabot commands and options</summary> <br />
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot mergewill merge this PR after your CI passes on it@dependabot squash and mergewill squash and merge this PR after your CI passes on it@dependabot cancel mergewill cancel a previously requested merge and block automerging@dependabot reopenwill reopen this PR if it is closed@dependabot closewill close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)@dependabot use these labelswill set the current labels as the default for future PRs for this repo and language@dependabot use these reviewerswill set the current reviewers as the default for future PRs for this repo and language@dependabot use these assigneeswill set the current assignees as the default for future PRs for this repo and language@dependabot use this milestonewill set the current milestone as the default for future PRs for this repo and language
You can disable automated security fix PRs for this repo from the Security Alerts page.
</details>
pr closed time in 6 days
push eventmozilla/hubs
commit sha 11978f511bb9bcea790f9ddcfc983df9ed012354
Bump lodash from 4.17.11 to 4.17.20 Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.20. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.20) Signed-off-by: dependabot[bot] <[email protected]>
commit sha 9bba5e2963178a091238d664d37e9c53245709d4
Merge pull request #3045 from mozilla/dependabot/npm_and_yarn/lodash-4.17.20 Bump lodash from 4.17.11 to 4.17.20
push time in 6 days
delete branch mozilla/hubs
delete branch : dependabot/npm_and_yarn/lodash-4.17.20
delete time in 6 days
PR merged mozilla/hubs
Bumps lodash from 4.17.11 to 4.17.20. <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/lodash/lodash/commit/ded9bc66583ed0b4e3b7dc906206d40757b4a90a"><code>ded9bc6</code></a> Bump to v4.17.20.</li> <li><a href="https://github.com/lodash/lodash/commit/63150ef7645ac07961b63a86490f419f356429aa"><code>63150ef</code></a> Documentation fixes.</li> <li><a href="https://github.com/lodash/lodash/commit/00f0f62a979d2f5fa0287c06eae70cf9a62d8794"><code>00f0f62</code></a> test.js: Remove trailing comma.</li> <li><a href="https://github.com/lodash/lodash/commit/846e434c7a5b5692c55ebf5715ed677b70a32389"><code>846e434</code></a> Temporarily use a custom fork of <code>lodash-cli</code>.</li> <li><a href="https://github.com/lodash/lodash/commit/5d046f39cbd27f573914768e3b36eeefcc4f1229"><code>5d046f3</code></a> Re-enable Travis tests on <code>4.17</code> branch.</li> <li><a href="https://github.com/lodash/lodash/commit/aa816b36d402a1ad9385142ce7188f17dae514fd"><code>aa816b3</code></a> Remove <code>/npm-package</code>.</li> <li><a href="https://github.com/lodash/lodash/commit/d7fbc52ee0466a6d248f047b5d5c3e6d1e099056"><code>d7fbc52</code></a> Bump to v4.17.19</li> <li><a href="https://github.com/lodash/lodash/commit/2e1c0f22f425e9c013815b2cd7c2ebd51f49a8d6"><code>2e1c0f2</code></a> Add npm-package</li> <li><a href="https://github.com/lodash/lodash/commit/1b6c282299f4e0271f932b466c67f0f822aa308e"><code>1b6c282</code></a> Bump to v4.17.18</li> <li><a href="https://github.com/lodash/lodash/commit/a370ac81408de2da77a82b3c4b61a01a3b9c2fac"><code>a370ac8</code></a> Bump to v4.17.17</li> <li>Additional commits viewable in <a href="https://github.com/lodash/lodash/compare/4.17.11...4.17.20">compare view</a></li> </ul> </details> <details> <summary>Maintainer changes</summary> <p>This version was pushed to npm by <a href="https://www.npmjs.com/~bnjmnt4n">bnjmnt4n</a>, a new releaser for lodash since your current version.</p> </details> <br />
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.
<details> <summary>Dependabot commands and options</summary> <br />
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot mergewill merge this PR after your CI passes on it@dependabot squash and mergewill squash and merge this PR after your CI passes on it@dependabot cancel mergewill cancel a previously requested merge and block automerging@dependabot reopenwill reopen this PR if it is closed@dependabot closewill close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)@dependabot use these labelswill set the current labels as the default for future PRs for this repo and language@dependabot use these reviewerswill set the current reviewers as the default for future PRs for this repo and language@dependabot use these assigneeswill set the current assignees as the default for future PRs for this repo and language@dependabot use this milestonewill set the current milestone as the default for future PRs for this repo and language
You can disable automated security fix PRs for this repo from the Security Alerts page.
</details>
pr closed time in 6 days
push eventmozilla/hubs
commit sha 50759f04859f06cce6e077d13cc67d55c2c873fd
Add feature panels to the landing page
commit sha 592968fe91aeb60497284163b1cc529dade4fae1
Exclude the basis transcoder from eslint. Shaves 40% off linting time
commit sha 840848dc7e307877f069b04a593a7a010eaa5f1f
Move copy to locale strings
commit sha 02284844601ffc66fb78e2c8fe3216c2c1719028
mention no VR headset necessary in copy
commit sha 59cda6244f247aa171e2fc69eb483212243be909
tweak copy
commit sha 878402caccfae9188b5e5eb62ad85527e9c9a829
Use underscores not dashes
commit sha eabc85d4a54d7257b891fb7adcfad46c55042342
Merge pull request #3209 from mozilla/feature/landing-page-panels Landing page panels
push time in 6 days
PR merged mozilla/hubs
Adds panels to the landing page describing Hubs' core features.
The panels are behind an internal feature flag and disabled by default. The images in the panels must also be configured using internal app settings (accessed via /admin#/app-settings?show_internal_configs=true). The panels are hidden if there would otherwise be user-favorited rooms or public rooms on the landing page.

pr closed time in 6 days
push eventmozilla/hubs
commit sha 878402caccfae9188b5e5eb62ad85527e9c9a829
Use underscores not dashes
push time in 6 days
Pull request review commentmozilla/hubs
images.company_logo = { category = "images", type = "file", name = "Company Logo images.home_background = { category = "images", type = "file", name = "Home background", description = "Background image on the home page." } images.editor_logo = { category = "images", type = "file", internal = "true" }+images.landing_rooms_thumb = { category = "images", type = "file", internal = "true" }+images.landing_communicate_thumb = { category = "images", type = "file", internal = "true" }+images.landing_media_thumb = { category = "images", type = "file", internal = "true" }
It's a good thought, but this particular PR is specifically meant for HMC, which is why it's disabled by default and the flags are internal. I think it's a good idea to consider enabling something like this for HC, but that's a bit of a bigger discussion around the whole redesign and general site customization that we're intentionally side-stepping in this PR.
comment created time in 6 days
Pull request review commentmozilla/hubs
"home.terms_of_use": "Terms of Use", "home.made_with_love": "made with 🦆 by ", "home.environment_author_by": " by ",+ "home.rooms-title": "Instantly create rooms",
Oh, nice catch.
comment created time in 6 days
Pull request review commentmozilla/hubs
"home.terms_of_use": "Terms of Use", "home.made_with_love": "made with 🦆 by ", "home.environment_author_by": " by ",+ "home.rooms-title": "Instantly create rooms",+ "home.rooms-blurb": "Share virtual spaces with your friends, co-workers, and communities. When you create a room with Hubs, you’ll have a private virtual meeting space that you can instantly share - no downloads or VR headset necessary.",+ "home.communicate-title": "Communicate naturally",+ "home.communicate-blurb": "Choose an avatar to represent you, put on your headphones, and jump right in. Hubs makes it easy to stay connected with voice and text chat to other people in your private room.",
I think you might have misread "headphones" as "headset"?
comment created time in 6 days
push eventmozilla/hubs
commit sha 59cda6244f247aa171e2fc69eb483212243be909
tweak copy
push time in 6 days
push eventmozilla/hubs
commit sha 02284844601ffc66fb78e2c8fe3216c2c1719028
mention no VR headset necessary in copy
push time in 7 days
Pull request review commentmozilla/hubs
!.eslintrc.js src/vendor/*+src/loaders/basis_transcoder.worker.js
Snuck this in here. This worker is a large, minified vendor file. It adds 40% more time to the eslint check, so it's best to ignore it.
comment created time in 7 days
PR opened mozilla/hubs
Adds panels to the landing page describing Hubs' core features.
The panels are behind an internal feature flag and disabled by default. The images in the panels must also be configured using internal app settings (accessed via /admin#/app-settings?show_internal_configs=true). The panels are hidden if there would otherwise be user-favorited rooms or public rooms on the landing page.

pr created time in 7 days
push eventmozilla/hubs
commit sha 840848dc7e307877f069b04a593a7a010eaa5f1f
Move copy to locale strings
push time in 7 days
Pull request review commentmozilla/hubs
const MAX_VOLUME = 8; const SMALL_STEP = 1 / (VOLUME_LABELS.length / 2); const BIG_STEP = (MAX_VOLUME - 1) / (VOLUME_LABELS.length / 2); +// Inserts analyser and gain nodes after audio source.+// Analyses audio source volume and adjusts gain value+// to make it in a certain range.+class AudioNormalizer {+ constructor(audio) {+ this.audio = audio;+ this.analyser = audio.context.createAnalyser();+ this.compressor = audio.context.createDynamicsCompressor();+ this.connected = false;++ // To analyse volume, 32 fftsize may be good enough+ this.analyser.fftSize = 32;+ this.gain = audio.context.createGain();+ this.timeData = new Uint8Array(this.analyser.frequencyBinCount);+ this.volumes = [];+ this.volumeSum = 0;++ // To protect user's ears, we insert compressor in case of misguessing the volume.+ // Threshold -30 is just an arbitary number so far.+ this.compressor.threshold.setValueAtTime(-30, audio.context.currentTime);+ }++ apply() {+ if (window.APP.store.state.preferences.audioNormalization) {+ if (!this.connected) {+ this.connect();+ }+ } else {+ if (this.connected) {+ this.disconnect();+ }+ return;+ }++ // Adjusts volume in "a rule of the thumb" way+ // Any better algorithm?++ // Regards the RMS of time-domain data as volume.+ // Is this a right approach?+ // Using the RMS of frequency-domain data would be another option.+ this.analyser.getByteTimeDomainData(this.timeData);+ const squareSum = this.timeData.reduce((sum, num) => sum + Math.pow(num - 128, 2), 0);+ const volume = Math.sqrt(squareSum / this.analyser.frequencyBinCount);+ const baseVolume = window.APP.store.state.preferences.audioNormalization;++ // Regards volume under certain threshold as "not speaking" and skips.+ // I'm not sure if 0.4 is an appropriate threshold.+ if (volume >= Math.min(0.4, baseVolume)) {+ this.volumeSum += volume;+ this.volumes.push(volume);+ // Sees only recent volume history because there is a chance+ // that a speaker changes their master input volume.+ // I'm not sure if 600 is an appropriate number.+ while (this.volumes.length > 600) {+ this.volumeSum -= this.volumes.shift();+ }+ // Adjusts volume after getting many enough volume history.+ // I'm not sure if 60 is an appropriate number.+ if (this.volumes.length >= 60) {+ const averageVolume = this.volumeSum / this.volumes.length;+ this.gain.gain.setTargetAtTime(baseVolume / averageVolume, this.audio.context.currentTime, 0.01);+ }+ }+ }++ connect() {+ // Hacks. THREE.Audio connects audio nodes when source is set.+ // If audio is not played yet, THREE.Audio.setFilters() doesn't+ // reset connections. Then manually caling .connect()/disconnect() here.+ // This might be a bug of Three.js and should be fixed in Three.js side?+ if (this.audio.source && !this.audio.isPlaying) {+ this.audio.disconnect();+ }+ // @TODO: Here overrides filters even if filters are already set other places.
I'm not familiar if we already use filters somewhere, or if three.js uses them behind the scenes, so I can't really comment on it. Just wanted to flag this TODO in case it actually needs actions and you missed it before merge.
comment created time in 8 days
startedendoplasmic/google-assistant
started time in 8 days
Pull request review commentmozilla/hubs
AFRAME.registerComponent("avatar-volume-controls", { return; } + if (!this.normalizer) {+ this.normalizer = new AudioNormalizer(audio);+ this.avatarAudioSource.el.addEventListener("sound-source-set", () => {+ const audio =+ this.avatarAudioSource && this.avatarAudioSource.el.getObject3D(this.avatarAudioSource.attrName);+ if (audio) {+ this.normalizer = new AudioNormalizer(audio);
Should you call this.normalizer.apply() after this?
comment created time in 9 days
Pull request review commentmozilla/hubs
export default class MessageDispatch { this.log(`Positional Audio ${shouldEnablePositionalAudio ? "enabled" : "disabled"}.`); } break;+ case "audioNormalization":+ {+ if (args.length === 1) {+ const factor = Number(args[0]);+ if (!isNaN(factor)) {+ const effectiveFactor = Math.max(0.0, Math.min(255.0, factor));+ window.APP.store.update({+ preferences: { audioNormalization: effectiveFactor }+ });+ if (factor) {+ this.log(`audioNormalization factor is set to ${effectiveFactor}.`);+ } else {+ this.log("audioNormalization is disabled.");+ }+ } else {+ this.log("audioNormalization command needs a valid number parameter.");+ }+ } else {+ this.log(+ "audioNormalization command needs a base volume number between 0 [no normalization] and 255. Default is 0. Recommended value is 4 if you enable."
I suggest slightly different wording:
"audioNormalization command needs a base volume number between 0 [no normalization] and 255. Default is 0. The recommended value is 4, if you would like to enable normalization."
comment created time in 9 days
Pull request review commentmozilla/hubs
const MAX_VOLUME = 8; const SMALL_STEP = 1 / (VOLUME_LABELS.length / 2); const BIG_STEP = (MAX_VOLUME - 1) / (VOLUME_LABELS.length / 2); +// Inserts analyser and gain nodes after audio source.+// Analyses audio source volume and adjusts gain value+// to make it in a certain range.+class AudioNormalizer {+ constructor(audio) {+ this.audio = audio;+ this.analyser = audio.context.createAnalyser();+ this.compressor = audio.context.createDynamicsCompressor();+ this.connected = false;++ // To analyse volume, 32 fftsize may be good enough+ this.analyser.fftSize = 32;+ this.gain = audio.context.createGain();+ this.timeData = new Uint8Array(this.analyser.frequencyBinCount);+ this.volumes = [];+ this.volumeSum = 0;++ // To protect user's ears, we insert compressor in case of misguessing the volume.+ // Threshold -30 is just an arbitary number so far.+ this.compressor.threshold.setValueAtTime(-30, audio.context.currentTime);+ }++ apply() {+ if (window.APP.store.state.preferences.audioNormalization) {+ if (!this.connected) {+ this.connect();+ }+ } else {+ if (this.connected) {+ this.disconnect();+ }+ return;+ }++ // Adjusts volume in "a rule of the thumb" way+ // Any better algorithm?++ // Regards the RMS of time-domain data as volume.+ // Is this a right approach?+ // Using the RMS of frequency-domain data would be another option.+ this.analyser.getByteTimeDomainData(this.timeData);+ const squareSum = this.timeData.reduce((sum, num) => sum + Math.pow(num - 128, 2), 0);+ const volume = Math.sqrt(squareSum / this.analyser.frequencyBinCount);+ const baseVolume = window.APP.store.state.preferences.audioNormalization;++ // Regards volume under certain threshold as "not speaking" and skips.+ // I'm not sure if 0.4 is an appropriate threshold.+ if (volume >= Math.min(0.4, baseVolume)) {+ this.volumeSum += volume;+ this.volumes.push(volume);+ // Sees only recent volume history because there is a chance+ // that a speaker changes their master input volume.+ // I'm not sure if 600 is an appropriate number.+ while (this.volumes.length > 600) {+ this.volumeSum -= this.volumes.shift();+ }+ // Adjusts volume after getting many enough volume history.+ // I'm not sure if 60 is an appropriate number.+ if (this.volumes.length >= 60) {+ const averageVolume = this.volumeSum / this.volumes.length;+ this.gain.gain.setTargetAtTime(baseVolume / averageVolume, this.audio.context.currentTime, 0.01);+ }+ }+ }++ connect() {+ // Hacks. THREE.Audio connects audio nodes when source is set.+ // If audio is not played yet, THREE.Audio.setFilters() doesn't+ // reset connections. Then manually caling .connect()/disconnect() here.+ // This might be a bug of Three.js and should be fixed in Three.js side?+ if (this.audio.source && !this.audio.isPlaying) {+ this.audio.disconnect();+ }+ // @TODO: Here overrides filters even if filters are already set other places.
Should this TODO be resolved before merge?
comment created time in 9 days
issue commentMozillaReality/hubs-discord-bot
1 week pass on Discord bot to identify tasks/plan forward
See also: #107
comment created time in 10 days
issue openedMozillaReality/hubs-discord-bot
Discord bot logs are full of messages about connection attempts to closed rooms
In order to continue debugging issues with the discord bot, we should resolve this issue that floods the bot's logs with errors about closed rooms.
created time in 10 days
startedtc39/proposal-set-methods
started time in 21 days
startedproject-chip/connectedhomeip
started time in 24 days
issue commentmozilla-mobile/fenix
Significant WebGL performance regression compared to Fennec
I can confirm that the performance issue appears to be fixed in the latest nightly from the play store (Nightly 83, 201002). Tested on my Samsung Galaxy S8, Android 9.
comment created time in a month
issue commentmozilla-mobile/fenix
Significant WebGL performance regression compared to Fennec
Yup, I'll be ready to test.
comment created time in a month
pull request commentmozilla/hubs
Fallback to default local model when there is an avatar load error
Yeah, I don't see a problem with grabbing one of the standard bots from our default set. You'd have to pack it as a GLB though. Also, now that you mention it, we'll have to keep in mind that this fallback will also be used on Hubs Cloud instances and it would require a custom client deploy to change it, so best to use something that is unbranded as possible.
comment created time in a month
issue commentbrianpeiris/quilt
@LakinduK Can you elaborate a bit on what you are asking for here?
comment created time in a month
Pull request review commentmozilla/reticulum
Add revocable API tokens using guardian_db
+defmodule Ret.Repo.Migrations.CreateGuardianDBTokensTable do+ use Ecto.Migration++ def change do+ create table(:guardian_tokens, primary_key: false) do+ add(:jti, :string, primary_key: true)+ add(:aud, :string, primary_key: true)+ add(:typ, :string)+ add(:iss, :string)+ add(:sub, :string)+ add(:exp, :bigint)+ add(:jwt, :text)+ add(:claims, :map)+ timestamps()+ end+ end+end
The SessionLockRepo is a special repo that we created to work around issues with migrations on Hubs Cloud (See #365 if you really want to dive deeper). In short, as a side effect of having SessionLockRepo, ecto.gen.migration creates two migration files. The one in the priv/session_lock_repo directory is actually redundant and should be deleted. Ideally we can find a way to prevent ecto.gen.migration from creating these files in the first place.
comment created time in a month
startedmooz/org-js
started time in a month
push eventmozilla/hubs
commit sha e40a4ea8f661005a81ee81590d9bb01f16e35d56
Add descriptions to npm scripts
commit sha 75aa0eb1cee4a2b04e0858457983cb8b1a87dc2d
Merge pull request #3046 from mozilla/scripts-info Add descriptions for npm scripts
push time in a month
PR merged mozilla/hubs
Using npm-scripts-info, you can now run npm run info to get descriptions of our npm scripts.

pr closed time in a month
push eventmozilla/hubs
commit sha 32afccf3ebc74b93a0286baf26adf4de320ae99e
Fix scene button styling
commit sha 878ae6399343bf3f6c4af563a6cc8b446c67d13b
Merge pull request #3053 from mozilla/fix-scene-button-styling Fix scene button styling
push time in a month