Augmented Perception
Remembering the past; augmented perception is a project by Janus developer bai in which he crawled and visualized the web of JanusXR virtual worlds people created and linked together
Silk Road
Thinking about what history can teach us about how to connect disparate virtual worlds together.
However,
Night Sky
In retrospect I think I was too heads down thinking about how to solve the metavese alignment problem.
When I added this night sky shader to The Street world in Webaverse I was awestruck by the beauty on my screen. Even if the skysphere was fictional, it dawned on me how looking out into the cyberspace cosmos made me feel like I was part of something bigger.
what if the stars were distant virtual worlds? and when you look up you see constellations that visualize the links / portals connecting between some of them? tweet
Ancient civilizations found inspiration in the stars and constellations in the night sky. They saw them as more than just celestial bodies; they saw stories, myths, and divine beings in the heavens. The stars guided navigation, marked the passage of time, and influenced agricultural activities. They became a part of cultural identity, passed down through generations, and played a role in shaping religious beliefs and rituals.
This script formats the raw JSON into just what we need by display the URLs for all hyperfy_portals
. Keep in mind though that traversal can happen from all sorts of other objects, such as images / zones / models. I think for now, hyperfy_portals
has an intentional and easy to understand context better for literacy when explaining the project to others.
import json
import sys
if len(sys.argv) != 2:
print("Usage: python parse_json.py <filename>")
sys.exit(1)
filename = sys.argv[1]
with open(filename, "r") as file:
data = json.load(file)
output = []
for item in data:
item_data = {
"id": item["id"],
"title": item["title"],
"description": item["description"],
"image": item["image"],
"slug": item["slug"]
}
entities = json.loads(item["entities"])
portals = []
for entity in entities:
if entity["id"] == "hyperfy-portal":
if "state" in entity and "$fields" in entity["state"] and "url" in entity["state"]["$fields"]:
url = entity["state"]["$fields"]["url"]
portals.append({
"url": url
})
if portals:
item_data["hyperfy_portals"] = portals
output.append(item_data)
# Print the output as a JSON string
print(json.dumps(output, indent=2))
#!/bin/bash
mkdir -p circle
for file in *.png; do
convert "${file}" \( +clone -threshold -1 -negate -fill white -draw "circle $(identify -format %w "${file}" | awk '{print $1/2}'), $(identify -format %h "${file}" | awk '{print $1/2}') $(identify -format %w "${file}" | awk '{print $1/2}'), 0" \) \
-alpha Off -compose copy_opacity -composite "circle/${file}"
done
img-nodes example
<!DOCTYPE html>
<html>
<head>
<style>
body, html {
height: 100%;
width: 100%;
margin: 0;
overflow: hidden;
}
#3d-graph {
height: 100%;
width: 100%;
}
</style>
<script src="//unpkg.com/three"></script>
<script src="//unpkg.com/3d-force-graph"></script>
</head>
<body>
<div id="3d-graph"></div>
<script type="importmap">{ "imports": { "three": "https://unpkg.com/three/build/three.module.js" }}</script>
<script type="module">
const ORIGIN = 'https://hyperfy.io';
function urlToAbsolute(url) {
if (!url) return url;
if (url.startsWith('http')) {
// Already an absolute URL
return url;
}
if (url.startsWith('/')) {
// Relative URL starting with "/"
return ORIGIN + url;
}
// Assuming the URL is a slug or path
return ORIGIN + '/' + url;
}
// Load JSON data from file
fetch('data3.json')
.then(response => response.json())
.then(data => {
const nodes = data.map(item => {
const imageName = item.image ? item.image.split('/').pop() : '';
const img = `imgs/circle/${imageName || 'placeholder.png'}`;
return {
id: item.id,
img: img,
title: item.title,
slug: item.slug,
hyperfy_portals: item.hyperfy_portals || []
};
});
const links = [];
nodes.forEach(node => {
node.hyperfy_portals.forEach(portal => {
if (typeof portal.url === 'string') {
const targetUrl = urlToAbsolute(portal.url);
const targetNode = nodes.find(n => n.hyperfy_portals.some(p => urlToAbsolute(p.url) === targetUrl));
if (targetNode) {
links.push({
source: node.id,
target: targetNode.id
});
}
}
});
});
const gData = {
nodes,
links
};
const Graph = ForceGraph3D({ controlType: 'fly' })
(document.getElementById('3d-graph'))
.nodeThreeObject(({ img }) => {
const imgTexture = new THREE.TextureLoader().load(img);
imgTexture.colorSpace = THREE.SRGBColorSpace;
const material = new THREE.SpriteMaterial({ map: imgTexture });
const sprite = new THREE.Sprite(material);
sprite.scale.set(12, 12);
return sprite;
})
.nodeLabel(({ title, slug }) => `Name: ${title || 'N/A'} Slug: ${slug}`)
.onNodeHover(node => {
if (!node) {
document.body.style.cursor = 'default';
} else {
document.body.style.cursor = 'pointer';
}
})
.linkWidth(1) // Adjust the line thickness here
.graphData(gData);
const bloomPass = new UnrealBloomPass();
bloomPass.strength = 1.2;
bloomPass.radius = 1;
bloomPass.threshold = 0.1;
Graph.postProcessingComposer().addPass(bloomPass);
})
.catch(error => {
console.error('Error loading data:', error);
});
</script>
</body>
</html>