poppenhuis (Dutch for "dollhouse") is a space for sharing collections and their 3D scans.

Have a collection you care about? of pottery? of sculptures? of guitars? of cars? of cakes? of plants? of dolls?

They're welcome to live here too.

The following (6 users) have collections:

Why?

When I was a kid, I used to watch an Australian TV show called Collectors. Each week a hobbyist collector would get 15 minutes to show off. Sadly, the show ended in 2011.

I think we are deprived of a good medium to share the stories of our cherished possessions clearly and easily. Photos alone are insufficient, and long form video is hard to make and maintain.

I believe that recent developments in photogrammetry and VR offer us a better medium, and I have sought to bring them to poppenhuis.

I hope some collections find a home here.

What file formats can poppenhuis render?

poppenhuis uses model-viewer for rendering 3D models, which only renders .gltf/.glb files.

Ideally poppenhuis would also support .ply-based Gaussian splats, perhaps with Spark. PRs welcome.

What app should I use to scan to .gltf/.glb files?

I personally use Polycam in LiDAR mode. The produced models, while jank and low poly, are small, compressed, easy to edit, and dimensionally accurate.

I also like Scaniverse, but I exclusively use it for Gaussian splatting, and have not used its LiDAR mode.


Want to upload your collections to poppenhuis?

Go to /auth and create an account. Then you can create a user profile, and your first collection.

Want to load your collections from an Are.na user profile?

Enter an Are.na profile slug. Only channels whose description includes poppenhu.is will be loaded, and only blocks uploaded as .glb files within those channels will be displayed.

ENTER SLUG ABOVE

You can add structured metadata to your Are.na blocks by including YAML in the description.

Everything after a --- divider will be parsed as YAML and used to set item metadata fields, for example:

My beautiful ceramic vase, hand-thrown on the wheel.
---
formalName: "Ceramic Vase #42"
releaseDate: "2023-10-15"
manufacturer: "Jane Smith"
material: 
  - "stoneware clay"
  - "celadon glaze"
acquisitionDate: "2023-11-01"
captureDevice: "iPhone 15 Pro"
captureMethod: "LiDAR"
Want to load your collections from a 3rd party manifest?

Your 3rd party manifest will be merged with poppenhuis's 1st party manifest, and the manifest URL will be stored in ?manifest= query param so you can share your collections with others.

Manifest schema
type Manifest = User[];

interface User {
  id: string;
  name: string;
  bio?: string;
  collections: Collection[];
}

interface Collection {
  id: string;
  name: string;
  description?: string;
  items: Item[];
}

export const ITEM_FIELD_DESCRIPTIONS = {
  formalName: "A more specific name (like a model number or a scientific name) than the general name.",
  model: "The path to the 3D model. Only glTF/GLB models are supported.",
  alt: "Custom text that will be used to describe the model to viewers who use a screen reader or otherwise depend on additional semantic context to understand what they are viewing.",
  poster: "The image to be displayed instead of the model it is loaded and ready to render.",
  releaseDate: `The release date and the manufacture date are subtly different. The release date is the date this item's specific variant was made available to the public. The manufacture date is the date the item was actually made.
      e.g. while the iPhone SE 1 was released in 2016, it was manufactured up until 2018.`,

  // YAML parsing feature for Are.na integration
  yamlInDescription: `You can include YAML metadata in Are.na block descriptions by adding a "---" divider.
Everything before "---" becomes the description, everything after is parsed as YAML that can set Item fields.

Example Are.na block description:
This is my beautiful sculpture made from clay.
---
formalName: "Clay Sculpture #42"
releaseDate: "2023-10-15"
manufacturer: "Artist Name"
material: 
  - "clay"
  - "glaze"
acquisitionDate: "2023-11-01"
captureDevice: "iPhone 15 Pro"
captureMethod: "LiDAR"

If there's no "---" divider, the entire description is treated normally.`
};

export interface Item {
  // required fields
  id: string;
  name: string;
  // model-viewer fields
  model: string;
  poster?: string;
  alt?: string;
  // abstract details
  formalName?: string;
  releaseDate?: string;
  description?: string;
  // material reality
  manufacturer?: string;
  manufactureDate?: string;
  manufactureLocation?: string;
  material?: string[];
  // acquisition
  acquisitionDate?: string;
  acquisitionLocation?: string;
  // post-acquisition
  storageLocation?: string;
  // capture
  captureDate?: string;
  captureLocation?: string;
  captureLatLon?: string;
  captureDevice?: string;
  captureApp?: string;
  captureMethod?: string;
  // misc
  customFields?: {
    [key: string]: string | undefined;
  };
}

Want to bake your collections into the bundle?

GitHub has everything we need for authenticated bulk uploading of models and metadata. Open a GitHub PR to the poppenhuis repo and:

  1. Upload your .gltf/.glb models to //public/models/
  2. Add your metadata to //src/manifest.ts. Baking the metadata into the bundle keeps the app snappy.

Credits and inspiration
Technical challenges

A lot of this app was actually really annoying to build. Particularly frustrating components were:

  • Loading and interleaving data from 4 different backends (Firebase, 3rd party manifest, Are.na, and bundle)
  • Layout stability when changing between screens
  • Laying out the VR scene
  • Laying out the Open Graph preview images
  • The Kitty printer integration and its various printing bugs