···11# Polymodel
2233-Polymodel is an AT Protocol-native model/project sharing app: roughly “Thingiverse on atproto.”
33+Polymodel (currently hosted intermittently at [polymodel.space](https://polymodel.space)) is an atproto-native 3D model sharing app: roughly “Thingiverse/Printables on atproto, but good.”
44+55+It's currently somewhere between "proof of concept" and "functional alpha". The core things work, including very basic social features, but there is a lot left to build and a lot of usability improvements needed and bugs to fix.
66+77+You can upload and share STL, STEP, OBJ, and 3MF files, as well as a couple of other incidental formats (GLTF, GLB), download them, preview them, add images, instructional text, tag them, and so on. You can follow other users, like or save their creations.
88+99+## Lexicons and data model
1010+1111+ALL lexicons currently in use should be expected to evolve in breaking ways in the near future, as I refine the desired semantics. They remain unpublished for this reason.
1212+1313+#### Core thing
1414+1515+A 'part' is a file with metadata; a name, dimensions, units, notes, format, preview images, attribution links, and so on. A 'model' is made up of multiple parts, and can represent a thing in itself, or something like a variant of something. A 'thing' is sort of the major project grouping, and includes more detailed text fields, instructions, multiple models, and so on. So for example, *Gridfinity* might be a 'thing', with all the different parts the maker designed as part of the system being 'parts', arranged into 'models'.
41655-The initial concept is intentionally small:
1717+Currently 'thing' is the only real grouping exposed top-level, but this isn't the long-term intent. Loose 'parts' and 'models' and so on are intended to be surfacable, at least for the user that uploaded them.
61877-- a lexicon for printable/model projects;
88-- a profile-oriented publishing surface;
99-- likes/saves and basic social feedback;
1010-- feeds for recent projects, hot projects, and per-profile project streams;
1111-- an in-browser STL viewer.
1919+#### Collaboration and Remixing
12201313-It is also a testbed for a highly integrated agent workflow built around Polytoken, Jira, Confluence, jj workspaces, and strong review gates.
2121+The current 'thing'-related types have a couple of reference fields, one for "derived from" relations, and the other for "indented to work with" relations. These are pretty preliminary and I'm still working out the semantics I want here. One goal of mine is to make it so that 'derived from' attribution in the interface is more or less automatic, even if the uploader didn't explcitly remix, likely via some form of perceptual hashing. I don't intend to include more than minimal in-browser editing.
2222+2323+Things like 'makes' or 'printer/slicer configs' and gcode are intended to be added as well. 'part' has a very preliminary take on print settings which *will* change, and the lexicons for "hey i made this `<link>`" straight up don't exist yet.
2424+2525+#### The rest
2626+2727+There are tags (currently exposed in the publish UI only, self-applied), intended to be user-supplied and/or community-applied. These are intended as curation and discoverability tools, not for moderation. Polymodel will have something more like moderation labels as well. Models and things have mandatory fields for license, so that copyright and use of original work is very clear. "All rights reserved" models or things will optionally be ineligible for remixing. The default is currently CC-BY-4.0.
2828+2929+There are lists (not currently exposed in the UI). There is the ability to save a model, bookmark it. Currently this is public, it will be made private. There are 'likes' and profiles with follows (currently using unidirectional follow semantics, this will likely evolve to an optional bidirectional request/accept pattern).
3030+3131+It has basic search and simple aggregated global and author feeds.
3232+3333+> Larger text fields will in future support some subset of Weaver-style Markdown, once I port Weaver to Jacquard 0.12.X and fix some more bugs in its editor. I also intend to support other types of 3D content not intended for printing, including models for use in animation or video game production, or things like gaussian splats and point clouds.
3434+3535+## Architecture and Evolution
3636+3737+The current design is a monolithic Dioxus fullstck webapp+appview server, acting as an OAuth (potentially confidential) client. It backfills and tails the firehose via [hydrant](https://hydrant.klbr.net/) into its Fjall data store. That event stream is teed and written to an SQLite database for additional indexing, which is currently used as the primary read target and to support immediate readback of user writes. This is very likely to change, perhaps by sharding the SQLite database by DID and/or moving more into the Fjall store.
3838+3939+It also intends to support the draft spec for atproto permissioned data, for features such as drafts, private sharing, private lists, and so on. The core primitives will land upstream in Jacquard, and the concrete implementation will be a separate service binary from the main app server, ideally somewhat agnostic to the specifics of the app, acting as space host and permission broker.
144015411642## Development
···19452046```sh
2147nix develop
4848+# or
4949+direnv allow
2250```
23512452Common commands:
···3159just serve # Dioxus dev server
3260```
33613434-`just serve` starts against the current projection database without seeding demo
6262+`just serve` starts against the current databases without seeding demo
3563content. For browser e2e or a local demo feed, opt in explicitly:
3664`POLYMODEL_SAMPLE_DATA=auto just serve`.
37653866## Stack
39674040-- Rust 2024 / nightly
4168- Dioxus 0.7
4269- Jacquard 0.12
4343-- Nix flake dev shell
4444-- just command runner
7070+- Hydrant for backfill (used as a library)
+6-5
lexicons/actor/defs.json
···1111 "handle": { "type": "string" },
1212 "displayName": { "type": "string" },
1313 "description": { "type": "string" },
1414- "avatar": { "type": "string", "format": "uri", "description": "Resolved avatar URL (CDN). Null until the app view resolves the polymodel profile avatar blob." },
1414+ "avatar": {
1515+ "type": "string",
1616+ "format": "uri",
1717+ "description": "Resolved avatar URL (CDN). Null until the app view resolves the polymodel profile avatar blob."
1818+ },
1519 "record": { "type": "unknown", "description": "The raw space.polymodel.actor.profile record." },
1620 "defaultLicense": { "type": "string" },
1721 "pronouns": { "type": "string" },
···4347 "profileViewUnion": {
4448 "type": "union",
4549 "description": "Discriminates a polymodel-native actor (space.polymodel.actor.defs#profileView, hydrated from the local profile record + stats) from a bluesky-only actor (app.bsky.actor.defs#profileViewDetailed, fetched from the public AppView). Clients render based on $type.",
4646- "refs": [
4747- "space.polymodel.actor.defs#profileView",
4848- "app.bsky.actor.defs#profileViewDetailed"
4949- ],
5050+ "refs": ["space.polymodel.actor.defs#profileView", "app.bsky.actor.defs#profileViewDetailed"],
5051 "closed": true
5152 }
5253 }