Examples › ObjectDB › Object collection
Object collection
BAM's object library as a catalogue home, the way McMaster-Carr and a Shopify collection lay one out, over its public sample (366 objects): a big title per material with its count, a second heading only where the data has one (Plastics, Glass and Paper split into Medical and Food; Metals has no second layer), and inside each a tile per type with its count. The left rail filters to one group and gives every group back when clicked again; the switcher regroups the same rows by size (bins of the bounding-box volume), shape, type or source, and the rail follows it.
The .base file and its data
Every tab above is one entry of this file; the views read these rows. ⋯ in the toolbar copies the current view as YAML.
# BAM's object library as a catalogue home: the grouped gallery (docs/CONTRACT.md §20). Big section titles, a second
# heading level only where the data has one, a tile per type, a left rail that filters to one group, and a live
# grouping switcher. ObjectDB's home page consumes the same keys. The data is ObjectDB's public sample (366 objects:
# open-licence scans and BAM's generated primitives; source/snapshot.py).
# Check it: node bin/data-ui.mjs check <this file>
data: objects.json
facets:
- { as: nav, follow: groupBy, clear: true }
properties:
name: { displayName: Name }
family: { displayName: Material }
area: { displayName: Area }
type_name: { displayName: Type }
grade: { displayName: Grade }
size_class: { displayName: Size class }
bbox_volume_ml: { displayName: Size }
mass_g: { displayName: Mass }
geometry_class: { displayName: Shape }
source: { displayName: Source }
geometry: { displayName: Geometry }
views:
- type: cards
name: Home
order: [name, type_name, size_class, mass_g]
groupBy: { property: family }
subGroupBy: { property: area }
cardSize: 180
sections: true
tiles: { property: type_name, all: true, limit: 12 }
grouping: material
groupings:
- id: material
label: Material
groupBy: { property: family }
subGroupBy: { property: area }
tiles: { property: type_name, all: true, limit: 12 }
- id: size
label: Size
groupBy: { property: bbox_volume_ml, bins: [250, 1000, 5000], log: true, unit: mL }
tiles: { property: type_name, all: true, limit: 12 }
- id: shape
label: Shape
groupBy: { property: geometry_class }
tiles: { property: type_name, all: true, limit: 12 }
- id: type
label: Type
groupBy: { property: type_name }
- id: source
label: Source
groupBy: { property: source }
tiles: { property: type_name, all: true, limit: 12 }
switcher: segmented
- type: table
name: Objects
order: [name, family, type_name, grade, size_class, bbox_volume_ml, mass_g, geometry_class, source, geometry]
groupBy: { property: family }
fold: closed
// objects.json: 366 rows, 102 KB; the first 3
{
"id": "object-collection",
"title": "BAM object library (public sample)",
"titleProperty": "name",
"source": "ObjectDB's public sample (lane/object-db-public 809e9b2: open-licence scans and BAM's generated primitives; 366 rows, 12 columns)",
"properties": {
"id": {
"type": "text",
"hidden": true
},
"name": {
"type": "text"
},
"family": {
"type": "text",
"labels": {
"plastic": "Plastics",
"textile": "Textiles",
"paper": "Paper",
"composite": "Composites",
"other": "Other",
"metal": "Metals",
"glass": "Glass",
"electronic": "Electronics",
"ceramic": "Ceramics",
"organic": "Organics",
"rubber": "Rubber",
"wood": "Wood"
}
},
"area": {
"type": "text",
"derived": "Medical / Food for a plastic, glass or paper object of that grade; else none"
},
"type_name": {
"type": "text"
},
"grade": {
"type": "text"
},
"size_class": {
"type": "text"
},
"bbox_volume_ml": {
"type": "number",
"unitText": "mL",
"decimals": 0
},
"mass_g": {
"type": "number",
"unitText": "g",
"decimals": 1
},
"source": {
"type": "text",
"labels": {
"google-scanned-objects": "Google Scanned Objects",
"egad": "EGAD",
"synthetic": "Generated (synthetic)",
"generated": "Generated"
}
},
"geometry": {
"type": "text"
},
"geometry_class": {
"type": "text",
"labels": {
"long": "Long",
"irregular": "Irregular",
"flat": "Flat",
"cubic": "Cubic"
}
}
},
"rows": [
{
"id": "gen_foam-piece_00",
"name": "Foam piece (generated 00)",
"family": "plastic",
"type_name": "Foam piece",
"grade": "non-food",
"size_class": "1l",
"bbox_volume_ml": 878.915,
"mass_g": 9.38,
"source": "generated",
"geometry": "primitive (box)",
"geometry_class": "irregular",
"area": null
},
{
"id": "gen_foam-piece_01",
"name": "Foam piece (generated 01)",
"family": "plastic",
"type_name": "Foam piece",
"grade": "non-food",
"size_class": "750ml",
"bbox_volume_ml": 812.108,
"mass_g": 8.66,
"source": "generated",
"geometry": "primitive (box)",
"geometry_class": "irregular",
"area": null
},
{
"id": "gen_foam-piece_02",
"name": "Foam piece (generated 02)",
"family": "plastic",
"type_name": "Foam piece",
"grade": "non-food",
"size_class": "750ml",
"bbox_volume_ml": 719.107,
"mass_g": 7.67,
"source": "generated",
"geometry": "primitive (box)",
"geometry_class": "irregular",
"area": null
}
]
}README.md
# Object collection
BAM's object library as a catalogue home, the way McMaster-Carr and a Shopify collection lay one out, over its public
sample (366 objects): a big title per material with its count, a second heading only where the data has one (Plastics,
Glass and Paper split into Medical and Food; Metals has no second layer), and inside each a tile per type with its
count. The left rail filters to one group and gives every group back when clicked again; the switcher regroups the
same rows by size (bins of the bounding-box volume), shape, type or source, and the rail follows it.
- **App:** ObjectDB
- **Replaces:** ObjectDB's home page (object-database `site/`), which draws its own category sections and links; the
grouped gallery is the cards view with headers and sub-headers, so ObjectDB's home becomes one `.base` view.
- **Shows:** `type: cards` with `tiles: {property, all, limit}` (one tile per sub-category, "All …" first, "Every
Type (N)" when there are more), `subGroupBy` drawn as a sub-header only where its value exists, `groupings:` with
`grouping:` and the built-in `switcher: segmented`, a numeric group level with `bins:` (`< 250 mL`, `250 mL – 1 L`,
`1 L – 5 L`, `≥ 5 L`: 78 / 135 / 113 / 40 objects), and the rail's `as: nav` facet following the view's grouping
(`?family=metal`, `?bbox_volume_ml=250..<1000`).
- **Data:** `objects.json`, written by `source/snapshot.py`: ObjectDB's public sample only, the 366 objects
lane/object-db-public (809e9b2) vetted (`source/public_ids.txt`): 150 Google Scanned Objects (CC BY 4.0), 30 EGAD
shapes (BSD-3-Clause) and 186 of BAM's generated primitives. Columns: id, name, family, type, grade, size class,
bounding-box volume, mass, source, geometry and shape, plus a derived `area` (Medical / Food for plastic, glass and
paper; none elsewhere). No customers, mixes, streams, tags, supplier research or labellers; the rebuild fails closed
on any id or source outside the sample. No thumbnails: each tile draws a monogram.
The original UI it replaces
ObjectDB's home page (object-database site/), which draws its own category sections and links; the grouped gallery is the cards view with headers and sub-headers, so ObjectDB's home becomes one .base view.
What it shows
type: cards with tiles: {property, all, limit} (one tile per sub-category, "All …" first, "Every Type (N)" when there are more), subGroupBy drawn as a sub-header only where its value exists, groupings: with grouping: and the built-in switcher: segmented, a numeric group level with bins: (< 250 mL, 250 mL – 1 L, 1 L – 5 L, ≥ 5 L: 78 / 135 / 113 / 40 objects), and the rail's as: nav facet following the view's grouping (?family=metal, ?bbox_volume_ml=250..<1000).
Data
objects.json, written by source/snapshot.py: ObjectDB's public sample only, the 366 objects lane/object-db-public (809e9b2) vetted (source/public_ids.txt): 150 Google Scanned Objects (CC BY 4.0), 30 EGAD shapes (BSD-3-Clause) and 186 of BAM's generated primitives. Columns: id, name, family, type, grade, size class, bounding-box volume, mass, source, geometry and shape, plus a derived area (Medical / Food for plastic, glass and paper; none elsewhere). No customers, mixes, streams, tags, supplier research or labellers; the rebuild fails closed on any id or source outside the sample. No thumbnails: each tile draws a monogram.