town.walls.photo

walls.town

Documentation

A documented photo of a graffiti piece.

main record

A documented photo of a graffiti piece.

Record Key tid Timestamp-based ID

Properties

altText string Optional

Accessibility alt text describing the photo. Auto-generated by a vision model at admin time; editable. The site renders it as the image alt.

maxLength: 10000 bytesmaxGraphemes: 1000 graphemes
artists array of string Optional

Artist names. Free strings; a piece may have several.

maxLength: 20 items
aspectRatio ref #aspectRatio Optional

Pixel dimensions of the image, used for justified layout / to avoid reflow. Best-effort.

camera ref #camera Optional

No description available.

caption string Optional

Short visible description shown under the artist-name title on the photo page. Was the title field; the title is now always the artist names.

maxLength: 10000 bytesmaxGraphemes: 1000 graphemes
capturedAt string datetime Optional

When the photo was taken (EXIF DateTimeOriginal), if known.

createdAt string datetime Required

Record creation time.

grainPost ref com.atproto.repo.strongRef Optional

strongRef to a grain post serving as the photo. Alternative to image (exactly one of image/grainPost required, app-enforced).

image blob Optional

The displayed photo. Optional in schema; exactly one of image or grainPost is required (enforced in app code).

maxSize: 4.0 MB
location ref #location Optional

No description available.

syndication array of ref #syndicationLeg Optional

Syndicated copies of this photo published as their own atproto records (bsky post, grain gallery, site doc, currents save, …). Machine-written by the syndication step — one entry per platform. Open set: adding a platform needs no lexicon change.

maxLength: 20 items
tags array of string Optional

Faceted tags. Conventions (parsed/enforced in app code, not the lexicon): kind:<piece|throwup|tag|mural|sticker|roller|wheatpaste|other> (exactly one expected), crew:<name>, surface:<wall|truck|pole|shutter|...>. Plus freeform tags (e.g. "trackside", "two-color").

maxLength: 40 items
View raw schema
{
  "key": "tid",
  "type": "record",
  "record": {
    "type": "object",
    "required": [
      "createdAt"
    ],
    "properties": {
      "tags": {
        "type": "array",
        "items": {
          "type": "string"
        },
        "maxLength": 40,
        "description": "Faceted tags. Conventions (parsed/enforced in app code, not the lexicon): kind:<piece|throwup|tag|mural|sticker|roller|wheatpaste|other> (exactly one expected), crew:<name>, surface:<wall|truck|pole|shutter|...>. Plus freeform tags (e.g. \"trackside\", \"two-color\")."
      },
      "image": {
        "type": "blob",
        "accept": [
          "image/*"
        ],
        "maxSize": 4000000,
        "description": "The displayed photo. Optional in schema; exactly one of image or grainPost is required (enforced in app code)."
      },
      "camera": {
        "ref": "#camera",
        "type": "ref"
      },
      "altText": {
        "type": "string",
        "maxLength": 10000,
        "description": "Accessibility alt text describing the photo. Auto-generated by a vision model at admin time; editable. The site renders it as the image alt.",
        "maxGraphemes": 1000
      },
      "artists": {
        "type": "array",
        "items": {
          "type": "string"
        },
        "maxLength": 20,
        "description": "Artist names. Free strings; a piece may have several."
      },
      "caption": {
        "type": "string",
        "maxLength": 10000,
        "description": "Short visible description shown under the artist-name title on the photo page. Was the title field; the title is now always the artist names.",
        "maxGraphemes": 1000
      },
      "location": {
        "ref": "#location",
        "type": "ref"
      },
      "createdAt": {
        "type": "string",
        "format": "datetime",
        "description": "Record creation time."
      },
      "grainPost": {
        "ref": "com.atproto.repo.strongRef",
        "type": "ref",
        "description": "strongRef to a grain post serving as the photo. Alternative to image (exactly one of image/grainPost required, app-enforced)."
      },
      "capturedAt": {
        "type": "string",
        "format": "datetime",
        "description": "When the photo was taken (EXIF DateTimeOriginal), if known."
      },
      "aspectRatio": {
        "ref": "#aspectRatio",
        "type": "ref",
        "description": "Pixel dimensions of the image, used for justified layout / to avoid reflow. Best-effort."
      },
      "syndication": {
        "type": "array",
        "items": {
          "ref": "#syndicationLeg",
          "type": "ref"
        },
        "maxLength": 20,
        "description": "Syndicated copies of this photo published as their own atproto records (bsky post, grain gallery, site doc, currents save, …). Machine-written by the syndication step — one entry per platform. Open set: adding a platform needs no lexicon change."
      },
      "externalLinks": {
        "type": "array",
        "items": {
          "ref": "#externalLink",
          "type": "ref"
        },
        "maxLength": 20,
        "description": "Manually-recorded off-protocol links (Instagram, Flickr, X, …). Tier-3 external syndication, recorded by hand — not automated posting."
      }
    }
  },
  "description": "A documented photo of a graffiti piece."
}
aspectRatio object

Image pixel dimensions. width/height are integers (e.g. for a 6000x4000 photo).

Properties

height integer Required

No description available.

minimum: 1
width integer Required

No description available.

minimum: 1
View raw schema
{
  "type": "object",
  "required": [
    "width",
    "height"
  ],
  "properties": {
    "width": {
      "type": "integer",
      "minimum": 1
    },
    "height": {
      "type": "integer",
      "minimum": 1
    }
  },
  "description": "Image pixel dimensions. width/height are integers (e.g. for a 6000x4000 photo)."
}
camera object

Best-effort capture metadata from EXIF or a grain record.

Properties

aperture string Optional

No description available.

focalLength string Optional

No description available.

iso integer Optional

No description available.

lens string Optional

No description available.

make string Optional

No description available.

model string Optional

No description available.

shutter string Optional

No description available.

View raw schema
{
  "type": "object",
  "properties": {
    "iso": {
      "type": "integer"
    },
    "lens": {
      "type": "string"
    },
    "make": {
      "type": "string"
    },
    "model": {
      "type": "string"
    },
    "shutter": {
      "type": "string"
    },
    "aperture": {
      "type": "string"
    },
    "focalLength": {
      "type": "string"
    }
  },
  "description": "Best-effort capture metadata from EXIF or a grain record."
}
externalLink object

A hand-recorded link to this piece on an off-protocol service.

Properties

label string Required

Platform/handle label; drives the icon on render. e.g. "instagram".

maxLength: 64 bytes
url string uri Required

The public URL.

maxLength: 2048 bytes
View raw schema
{
  "type": "object",
  "required": [
    "label",
    "url"
  ],
  "properties": {
    "url": {
      "type": "string",
      "format": "uri",
      "maxLength": 2048,
      "description": "The public URL."
    },
    "label": {
      "type": "string",
      "maxLength": 64,
      "description": "Platform/handle label; drives the icon on render. e.g. \"instagram\"."
    }
  },
  "description": "A hand-recorded link to this piece on an off-protocol service."
}
location object

Capture location. lat/lng are decimal-degree STRINGS: ATProto lexicons have no float type (only integer). Coordinates are stored AND rendered at full precision (the website plots them on its map page); the record is also public via listRecords, so exact coords are readable by anyone reading the repo directly.

Properties

lat string Optional

Decimal degrees, full precision. e.g. "37.77531".

lng string Optional

Decimal degrees, full precision. e.g. "-122.22417".

name string Optional

Optional human label, e.g. "E 12th St underpass".

View raw schema
{
  "type": "object",
  "properties": {
    "lat": {
      "type": "string",
      "description": "Decimal degrees, full precision. e.g. \"37.77531\"."
    },
    "lng": {
      "type": "string",
      "description": "Decimal degrees, full precision. e.g. \"-122.22417\"."
    },
    "name": {
      "type": "string",
      "description": "Optional human label, e.g. \"E 12th St underpass\"."
    }
  },
  "description": "Capture location. lat/lng are decimal-degree STRINGS: ATProto lexicons have no float type (only integer). Coordinates are stored AND rendered at full precision (the website plots them on its map page); the record is also public via listRecords, so exact coords are readable by anyone reading the repo directly."
}
syndicationLeg object

A syndicated copy of this photo as its own atproto record. Written by the syndication step; a platform's absence means that leg hasn't run.

Properties

platform string Required

Platform key (open set): bsky, grain, site, currents, longform, … The code-side registry maps keys to display names + URL builders.

maxLength: 32 bytes
View raw schema
{
  "type": "object",
  "required": [
    "platform",
    "ref"
  ],
  "properties": {
    "ref": {
      "ref": "com.atproto.repo.strongRef",
      "type": "ref",
      "description": "strongRef to the syndicated record."
    },
    "platform": {
      "type": "string",
      "maxLength": 32,
      "description": "Platform key (open set): bsky, grain, site, currents, longform, … The code-side registry maps keys to display names + URL builders."
    }
  },
  "description": "A syndicated copy of this photo as its own atproto record. Written by the syndication step; a platform's absence means that leg hasn't run."
}

Lexicon Garden

@