openapi: 3.0.3
info:
  title: Grudge Studio ObjectStore API
  description: Public API for Grudge Warlords game data — weapons, armor, materials, sprites, VFX, and more.
  version: 2.4.0
  contact:
    name: Grudge Studio
    url: https://grudgewarlords.com
    email: games@grudgestudio.org
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

servers:
  - url: https://molochdagod.github.io/ObjectStore
    description: GitHub Pages (static JSON)
  - url: https://objectstore.vercel.app
    description: Vercel (static + serverless)

tags:
  - name: Core
    description: Core game data (weapons, armor, materials, consumables)
  - name: Combat
    description: Skills, enemies, bosses, abilities
  - name: Sprites
    description: 2D sprites, VFX effects, sprite maps
  - name: World
    description: Classes, races, factions, professions, attributes
  - name: Engine
    description: Game engine data (units, maps, AI, animations)
  - name: grudgeDot
    description: Unified asset manifest for grudgeDot game engine
  - name: Worker
    description: Cloudflare Worker live API endpoints (objectstore.grudge-studio.com)
  - name: Serverless
    description: Vercel-only dynamic endpoints

paths:
  /api/v1/weapons.json:
    get:
      tags: [Core]
      summary: Get all weapons
      description: 119 weapons across 17 categories with stats, lore, abilities, passives
      responses:
        '200':
          description: Weapons data
          content:
            application/json:
              schema:
                type: object
                properties:
                  version: { type: string }
                  categories:
                    type: object
                    additionalProperties:
                      type: object
                      properties:
                        craftedBy: { type: string }
                        category: { type: string }
                        items:
                          type: array
                          items: { $ref: '#/components/schemas/Weapon' }

  /api/v1/armor.json:
    get:
      tags: [Core]
      summary: Get all armor
      description: 150 armor items (6 sets × 8 slots × 3 materials + gems) with stats, procs, set bonuses
      responses:
        '200': { description: Armor data }

  /api/v1/materials.json:
    get:
      tags: [Core]
      summary: Get all crafting materials
      description: 112 materials (ore, wood, cloth, leather, gems, herbs)
      responses:
        '200': { description: Materials data }

  /api/v1/consumables.json:
    get:
      tags: [Core]
      summary: Get all consumables
      description: 132 consumables — Chef foods, potions, engineer items
      responses:
        '200': { description: Consumables data }

  /api/v1/weaponSkills.json:
    get:
      tags: [Combat]
      summary: Get all weapon skills
      description: 473 weapon skills across 24 types with icons, cooldowns, effects
      responses:
        '200': { description: Weapon skills data }

  /api/v1/skills.json:
    get:
      tags: [Combat]
      summary: Get combat skills (legacy)
      description: 47 weapon skills with cooldowns, mana costs
      responses:
        '200': { description: Skills data }

  /api/v1/enemies.json:
    get:
      tags: [Combat]
      summary: Get all enemies
      description: 38 enemies across 8 tiers with abilities, drops, 3D asset paths
      responses:
        '200': { description: Enemies data }

  /api/v1/bosses.json:
    get:
      tags: [Combat]
      summary: Get all bosses
      description: 12 bosses with multi-phase mechanics, drops, Gouldstone chances
      responses:
        '200': { description: Bosses data }

  /api/v1/effectSprites.json:
    get:
      tags: [Sprites]
      summary: Get VFX effect sprites
      description: 147 VFX sprite sheets with frame data, categories, blend modes
      responses:
        '200': { description: Effect sprites data }

  /api/v1/abilityEffects.json:
    get:
      tags: [Sprites]
      summary: Get ability effects
      description: 209 abilities with effect chains and follow-ups
      responses:
        '200': { description: Ability effects data }

  /api/v1/sprites.json:
    get:
      tags: [Sprites]
      summary: Get sprite database
      description: 500+ icon paths organized by category
      responses:
        '200': { description: Sprites data }

  /api/v1/sprites2d.json:
    get:
      tags: [Sprites]
      summary: Get 2D sprites registry
      description: 5,485 2D sprites across 13 categories from RPG-MODULAR, betta-warlords, grudge-angeler, grudawars
      responses:
        '200':
          description: 2D sprites data
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Sprites2DResponse' }

  /api/v1/spriteMaps.json:
    get:
      tags: [Sprites]
      summary: Get sprite path mappings
      description: 246 sprite path mappings for weapons and armor icons
      responses:
        '200': { description: Sprite maps }

  /api/v1/classes.json:
    get:
      tags: [World]
      summary: Get all classes
      description: 4 classes — Warrior, Mage Priest, Worge, Ranger
      responses:
        '200': { description: Classes data }

  /api/v1/races.json:
    get:
      tags: [World]
      summary: Get all races
      description: 6 races — Human, Orc, Elf, Undead, Barbarian, Dwarf
      responses:
        '200': { description: Races data }

  /api/v1/factions.json:
    get:
      tags: [World]
      summary: Get all factions
      description: 3 factions — Crusade, Legion, Fabled
      responses:
        '200': { description: Factions data }

  /api/v1/attributes.json:
    get:
      tags: [World]
      summary: Get all attributes
      description: 8 attributes with formulas — STR, INT, VIT, DEX, END, WIS, AGI, TAC
      responses:
        '200': { description: Attributes data }

  /api/v1/professions.json:
    get:
      tags: [World]
      summary: Get all professions
      description: 5 crafting + 6 gathering professions, skill trees, 363+ recipes
      responses:
        '200': { description: Professions data }

  /api/v1/factionUnits.json:
    get:
      tags: [Engine]
      summary: Get faction units
      description: 19 RTS faction units across 3 factions
      responses:
        '200': { description: Faction units data }

  /api/v1/nodeUpgrades.json:
    get:
      tags: [Engine]
      summary: Get node upgrades
      responses:
        '200': { description: Node upgrades data }

  /api/v1/tileMaps.json:
    get:
      tags: [Engine]
      summary: Get tile maps
      responses:
        '200': { description: Tile maps data }

  /api/v1/animations.json:
    get:
      tags: [Engine]
      summary: Get animation library
      description: 210+ humanoid animations with retargeting support across 7 skeleton conventions. Includes weapon packs (Sword+Shield 49, Longbow 12, Pistol 21), harvesting (24), gestures (14), and rigging/conversion pipeline docs.
      responses:
        '200': { description: Animation library with rigging guide, categories, weapon packs, class defaults, character models, 2D sprite data }

  /api/v1/rendering.json:
    get:
      tags: [Engine]
      summary: Get rendering config
      responses:
        '200': { description: Rendering data }

  /api/v1/controllers.json:
    get:
      tags: [Engine]
      summary: Get camera/controller presets
      responses:
        '200': { description: Controllers data }

  /api/v1/terrain.json:
    get:
      tags: [Engine]
      summary: Get terrain presets
      responses:
        '200': { description: Terrain data }

  /api/v1/ai.json:
    get:
      tags: [Engine]
      summary: Get AI behavior trees
      responses:
        '200': { description: AI data }

  /api/v1/ecs.json:
    get:
      tags: [Engine]
      summary: Get ECS components
      responses:
        '200': { description: ECS data }

  /api/v1/grudgedot-assets.json:
    get:
      tags: [grudgeDot]
      summary: Get unified grudgeDot asset manifest
      description: 8,386 assets (icons, sprites, 3D models, audio, video) in a single manifest for grudgeDot
      responses:
        '200':
          description: grudgeDot asset manifest
          content:
            application/json:
              schema: { $ref: '#/components/schemas/grudgeDotManifest' }

  /api/v1/grudgedot-assets:
    get:
      tags: [grudgeDot]
      summary: Search/filter grudgeDot assets (Express)
      description: Paginated, filterable asset search when running the Express server
      parameters:
        - name: type
          in: query
          schema: { type: string, enum: [icon, sprite, model, audio, video] }
        - name: category
          in: query
          schema: { type: string }
        - name: search
          in: query
          schema: { type: string }
        - name: page
          in: query
          schema: { type: integer, default: 1 }
        - name: limit
          in: query
          schema: { type: integer, default: 200, maximum: 500 }
      responses:
        '200':
          description: Filtered asset results

  /api/v1/grudgedot-assets/categories:
    get:
      tags: [grudgeDot]
      summary: Get grudgeDot asset categories with counts
      responses:
        '200': { description: Category summary }

  # ── Cloudflare Worker — Item Collection Endpoints ──────────────────────────
  # Base URL: https://objectstore.grudge-studio.com
  # All endpoints return: { collection, total, count, limit, offset, items[] }
  # CORS headers are set automatically on all responses.

  /v1/relics:
    get:
      tags: [Worker]
      summary: List relics
      description: >
        Returns equippable relic items from master-relics.json. Supports filtering
        by category, tier, element, and slot. Undiscovered relics are never hidden
        (relics are always visible unlike artifacts).
      parameters:
        - name: q
          in: query
          schema: { type: string }
          description: Full-text search on name, id, or description
        - name: category
          in: query
          schema: { type: string, enum: [elemental, combat, defensive, utility] }
          description: Filter by relic category
        - name: tier
          in: query
          schema: { type: integer, minimum: 1, maximum: 8 }
          description: Filter by numeric tier (1–8)
        - name: element
          in: query
          schema: { type: string }
          description: Filter by element (e.g. frost, flame, storm)
        - name: slot
          in: query
          schema: { type: string, enum: [relic] }
          description: Filter by gear slot
        - name: limit
          in: query
          schema: { type: integer, default: 50, maximum: 500 }
        - name: offset
          in: query
          schema: { type: integer, default: 0 }
      responses:
        '200':
          description: Paginated relic list
          headers:
            Cache-Control:
              schema: { type: string }
              description: public, max-age=300
            Access-Control-Allow-Origin:
              schema: { type: string }
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ItemCollectionResponse' }
        '503': { description: Upstream data unavailable }

  /v1/relics/{id}:
    get:
      tags: [Worker]
      summary: Get a single relic
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
          description: Relic `id`, `uuid`, or name slug (e.g. relic-frost, RELC-…)
      responses:
        '200': { description: Relic item object }
        '404': { description: Relic not found }
        '503': { description: Upstream data unavailable }

  /v1/enchants:
    get:
      tags: [Worker]
      summary: List enchants
      description: >
        Returns Mystic-crafted enchants from master-enchants.json. Enchants are
        consumed on apply and permanently bake a stat bonus onto the target item.
      parameters:
        - name: q
          in: query
          schema: { type: string }
          description: Full-text search on name, id, or description
        - name: category
          in: query
          schema: { type: string }
          description: Filter by category (e.g. enchant)
        - name: tier
          in: query
          schema: { type: integer, minimum: 1, maximum: 8 }
          description: Filter by numeric tier (1–8)
        - name: target
          in: query
          schema: { type: string, enum: [weapon, armor] }
          description: Filter by applicable item type
        - name: limit
          in: query
          schema: { type: integer, default: 50, maximum: 500 }
        - name: offset
          in: query
          schema: { type: integer, default: 0 }
      responses:
        '200':
          description: Paginated enchant list
          headers:
            Cache-Control:
              schema: { type: string }
              description: public, max-age=300
            Access-Control-Allow-Origin:
              schema: { type: string }
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ItemCollectionResponse' }
        '503': { description: Upstream data unavailable }

  /v1/enchants/{id}:
    get:
      tags: [Worker]
      summary: Get a single enchant
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
          description: Enchant `id`, `uuid`, or name slug
      responses:
        '200': { description: Enchant item object }
        '404': { description: Enchant not found }
        '503': { description: Upstream data unavailable }

  /v1/infusions:
    get:
      tags: [Worker]
      summary: List infusions
      description: >
        Returns infusion essences from master-infusions.json. Infusions are consumed
        at the Mystic Enchanting Bench to advance an item toward its next tier.
      parameters:
        - name: q
          in: query
          schema: { type: string }
          description: Full-text search on name, id, or description
        - name: tier
          in: query
          schema: { type: integer, minimum: 1, maximum: 8 }
          description: Filter by numeric tier (1–8)
        - name: scope
          in: query
          schema: { type: string, enum: [universal, profession] }
          description: Filter by scope — universal essences drop from enemies; profession-scoped require unlock
        - name: profession
          in: query
          schema: { type: string }
          description: Filter by required profession (e.g. Mystic, Smith)
        - name: limit
          in: query
          schema: { type: integer, default: 50, maximum: 500 }
        - name: offset
          in: query
          schema: { type: integer, default: 0 }
      responses:
        '200':
          description: Paginated infusion list
          headers:
            Cache-Control:
              schema: { type: string }
              description: public, max-age=300
            Access-Control-Allow-Origin:
              schema: { type: string }
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ItemCollectionResponse' }
        '503': { description: Upstream data unavailable }

  /v1/infusions/{id}:
    get:
      tags: [Worker]
      summary: Get a single infusion
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
          description: Infusion `id` or `uuid`
      responses:
        '200': { description: Infusion item object }
        '404': { description: Infusion not found }
        '503': { description: Upstream data unavailable }

  /v1/artifacts:
    get:
      tags: [Worker]
      summary: List artifacts
      description: >
        Returns end-game magic weapons (Artifact category) from master-artifacts.json.
        Per D3, items with `discovery.hiddenUntilFound: true` are excluded by default.
        Pass `discovered=all` to include all artifacts regardless of discovery state.
      parameters:
        - name: q
          in: query
          schema: { type: string }
          description: Full-text search on name or description
        - name: tier
          in: query
          schema: { type: integer, minimum: 1, maximum: 8 }
          description: Filter by numeric tier (1–8)
        - name: artifactType
          in: query
          schema: { type: string }
          description: Filter by artifact sub-type (e.g. lightning, fire, arcane)
        - name: subtype
          in: query
          schema: { type: string }
          description: Filter by weapon sub-type (e.g. sword, staff, bow)
        - name: handedness
          in: query
          schema: { type: string, enum: ['1h', '2h', offhand] }
          description: Filter by handedness
        - name: discovered
          in: query
          schema: { type: string, enum: [all] }
          description: Pass `discovered=all` to include undiscovered artifacts
        - name: limit
          in: query
          schema: { type: integer, default: 50, maximum: 500 }
        - name: offset
          in: query
          schema: { type: integer, default: 0 }
      responses:
        '200':
          description: Paginated artifact list
          headers:
            Cache-Control:
              schema: { type: string }
              description: public, max-age=300
            Access-Control-Allow-Origin:
              schema: { type: string }
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ItemCollectionResponse' }
        '503': { description: Upstream data unavailable }

  /v1/artifacts/{id}:
    get:
      tags: [Worker]
      summary: Get a single artifact
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
          description: Artifact `uuid` or name slug (e.g. sword-of-the-storm)
      responses:
        '200': { description: Artifact item object }
        '404': { description: Artifact not found }
        '503': { description: Upstream data unavailable }

  /api/search:
    get:
      tags: [Serverless]
      summary: Search all game data
      description: Serverless search endpoint (Vercel only)
      parameters:
        - name: q
          in: query
          required: true
          schema: { type: string }
          description: Search query
        - name: type
          in: query
          schema:
            type: string
            enum: [all, weapons, armor, materials, consumables, enemies, bosses, skills, sprites]
            default: all
        - name: limit
          in: query
          schema: { type: integer, default: 50, maximum: 200 }
      responses:
        '200':
          description: Search results
          content:
            application/json:
              schema: { $ref: '#/components/schemas/SearchResponse' }

  /api/stats:
    get:
      tags: [Serverless]
      summary: Get aggregate stats
      description: Returns total counts for all data categories (Vercel only)
      responses:
        '200': { description: Stats data }

  /api/export:
    get:
      tags: [Serverless]
      summary: Bulk data export
      description: Download filtered game data as JSON or CSV (Vercel only)
      parameters:
        - name: type
          in: query
          required: true
          schema: { type: string, enum: [weapons, armor, materials, consumables, enemies, bosses, skills] }
        - name: tier
          in: query
          schema: { type: integer }
        - name: category
          in: query
          schema: { type: string }
        - name: format
          in: query
          schema: { type: string, enum: [json, csv], default: json }
      responses:
        '200': { description: Exported data }

components:
  schemas:
    ItemCollectionResponse:
      type: object
      description: Standard paginated response for item collection endpoints (/v1/relics, /v1/enchants, /v1/infusions, /v1/artifacts)
      properties:
        collection:
          type: string
          description: Source dataset name (e.g. master-relics)
        total:
          type: integer
          description: Total number of items after filtering
        count:
          type: integer
          description: Number of items in this page
        limit:
          type: integer
          description: Page size requested
        offset:
          type: integer
          description: Offset into the result set
        items:
          type: array
          items: { type: object }
          description: Array of item objects for this page

    Weapon:
      type: object
      properties:
        id: { type: string }
        name: { type: string }
        type: { type: string }
        lore: { type: string }
        stats:
          type: object
          properties:
            damageBase: { type: number }
            damagePerTier: { type: number }
            speedBase: { type: number }
            critBase: { type: number }
        basicAbility: { type: string }
        abilities: { type: array, items: { type: string } }
        signatureAbility: { type: string }
        passives: { type: array, items: { type: string } }

    Sprites2DResponse:
      type: object
      properties:
        totalSprites: { type: integer }
        generatedAt: { type: string }
        categories:
          type: object
          additionalProperties:
            type: object
            properties:
              count: { type: integer }
              items:
                type: array
                items:
                  type: object
                  properties:
                    name: { type: string }
                    path: { type: string }
                    category: { type: string }
                    subcategory: { type: string }
                    source: { type: string }

    grudgeDotManifest:
      type: object
      properties:
        version: { type: string }
        generated: { type: string, format: date-time }
        baseUrl: { type: string }
        totalAssets: { type: integer }
        types:
          type: object
          properties:
            icon: { type: integer }
            sprite: { type: integer }
            model: { type: integer }
            audio: { type: integer }
            video: { type: integer }
        categories:
          type: array
          items:
            type: object
            properties:
              type: { type: string }
              category: { type: string }
              count: { type: integer }
        assets:
          type: array
          items: { $ref: '#/components/schemas/grudgeDotAsset' }

    grudgeDotAsset:
      type: object
      properties:
        id: { type: string }
        name: { type: string }
        type: { type: string, enum: [icon, sprite, model, audio, video] }
        category: { type: string }
        subcategory: { type: string }
        url: { type: string, format: uri }
        previewUrl: { type: string, format: uri, nullable: true }
        tags: { type: array, items: { type: string } }
        format: { type: string }
        sizeBytes: { type: integer }
        metadata: { type: object }

    SearchResponse:
      type: object
      properties:
        query: { type: string }
        type: { type: string }
        totalResults: { type: integer }
        results:
          type: array
          items:
            type: object
            properties:
              type: { type: string }
              id: { type: string }
              name: { type: string }
