Market

repository·main·Indexed 42 days ago

https://github.com/pmndrs/market

A platform for discovering and downloading CC0-licensed 3D assets, including models, textures, and HDRIs. It features a built-in Material Editor using @react-three/fiber and @react-three/drei, a manifest-based Preloader for Three.js assets, and boilerplate generators for HDRI scenes and standard Three.js environments.

Tokens
4.7K
Snippets
16
Records
20
Agent score
54%

What's inside Market

  1. Overview of Market features

    main

    Market provides a platform for downloading CC0 (Creative Commons Zero) assets for 3D projects. Key features include:

    • Assets: Free, minified, and ready-to-use 3D models, textures, and HDRIs.
    • Starters: Boilerplate code for threejs and react-three-fiber.
    • Community Features: User accounts, asset requests, favorites, comments, and ratings.
    • Infrastructure: API endpoints and a CDN with caching.
    • Tools: A built-in Material Editor.
  2. Run Market locally

    main

    To run the Market project on your local machine for development or inspection, clone the repository, install dependencies using yarn, and start the development server.

    Note:

    • Login functionality is not functional in the local environment.
    • Environment keys are only required if you intend to perform operations that modify the database.
    git clone https://github.com/pmndrs/market
    cd market
    yarn
    yarn dev
  3. Implement a custom Resolver for the Preloader

    main

    To extend the Preloader with new asset types, implement a resolver object (or class) that adheres to the following interface:

    • type: A unique string identifying the asset type.
    • resolve(item): A function that takes an item from the manifest and returns a Promise. This promise should resolve with the item object augmented with the loaded asset (e.g., { ...item, texture }).
    • get(item, ...args): A function used to extract the loaded asset from the manifest item.
  4. Configure light settings via lightControls

    main

    The lightControls object defines the schema for controlling lighting parameters. It supports fine-grained adjustments for intensity, presets, and environmental lighting.

    Available Properties

    • intensity: A numeric slider control.
      • value: The current intensity.
      • min: Minimum value (0).
      • max: Maximum value (2).
      • step: Increment size (0.1).
      • label: Display name ('light intensity').
    • preset: A selection control for lighting styles.
      • value: The current preset (defaults to 'rembrandt').
      • options: ['rembrandt', 'portrait', 'upfront', 'soft']
    • environment: A selection control for the environment map.
      • value: The current environment (defaults to 'city').
      • options: ['', 'sunset', 'dawn', 'night', 'warehouse', 'forest', 'apartment', 'studio', 'city', 'park', 'lobby']
    export const lightControls = {
      intensity: {
        value: 0.1,
        min: 0,
        max: 2,
        step: 0.1,
        label: 'light intensity',
      },
      preset: {
        value: 'rembrandt',
        options: ['rembrandt', 'portrait', 'upfront', 'soft'],
      },
      environment: {
        value: 'city',
        options: [
          '',
          'sunset',
          'dawn',
          'night',
          'warehouse',
          'forest',
          'apartment',
          'studio',
          'city',
          'park',
          'lobby',
        ],
      },
    }
  5. Configure next-sitemap

    main

    The next-sitemap.config.js file is used to configure the next-sitemap package. It accepts an object with settings to define the base URL of your site and whether to automatically generate a robots.txt file.

    module.exports = {
      siteUrl: 'https://market.pmnd.rs/',
      generateRobotsTxt: true,
    }
  6. Setup a standard Three.js scene and lighting

    main

    The lightsAndSceneSetup snippet provides a boilerplate for initializing a standard Three.js environment, including:

    • A WebGLRenderer with shadow maps enabled (PCFSoftShadowMap).
    • A PerspectiveCamera and OrbitControls for navigation.
    • A basic lighting setup consisting of an AmbientLight and two PointLight instances configured to cast shadows.
    • Basic window resize event listeners.
    /* This is a conceptual usage of the lightsAndSceneSetup string */
    // The snippet initializes: renderer, scene, camera, controls, and lights.
    // It also attaches a resize listener to the window.
  7. Setup the Three.js render loop

    main

    The renderSetUp snippet provides the standard boilerplate for a Three.js animation loop, including:

    • An onResize function to handle window resizing and update the camera aspect ratio/renderer size.
    • An animate function using requestAnimationFrame.
    • A render function that updates controls and executes the renderer.
    /* This is a conceptual usage of the renderSetUp string */
    // The snippet provides: onResize(), animate(), and render().
  8. Use the Preloader class to manage asset loading

    main

    The Preloader class provides a centralized way to load various Three.js assets (like textures or GLTF models) using a manifest-based approach. To use it, you must first initialize it with one or more resolvers. Each resolver must be an object containing a type string, a resolve(item) method that returns a Promise, and a get(item, ...args) method to retrieve the loaded asset.

    Once initialized, you can call .load(manifest) with an array of asset objects. Each object in the manifest should have a type, id, and url. The load method returns a Promise that resolves when all assets are loaded. You can later retrieve specific assets using .get(id).

    import { preloader } from './loader/index.js';
    
    // 1. Initialize with resolvers
    preloader.init(new TextureResolver(renderer), new GLTFResolver());
    
    // 2. Define a manifest
    const manifest = [
      { id: 'my-texture', type: 'texture', url: 'textures/diffuse.jpg', version: '1.0' },
      { id: 'my-model', type: 'gltf', url: 'models/scene.gltf', version: '1.0' }
    ];
    
    // 3. Load assets
    await preloader.load(manifest);
    
    // 4. Retrieve assets by ID
    const texture = preloader.get('my-texture');
    const model = preloader.get('my-model');
  9. Fetch asset data via the dynamic API endpoint

    main

    The API endpoint /[type]/[name] allows you to retrieve specific assets, categories, creators, or teams from the market. The endpoint uses Supabase as the backend and returns cleaned data. All responses include a Cache-Control header set to s-maxage=86400, stale-while-revalidate for efficient caching.

    Endpoint Patterns

    1. Categories:

      • URL: /[assetType]/categories (where assetType is typically models or similar).
      • Behavior: Returns a grouped list of categories. Each category object contains the category name and an array of assets belonging to that category.
      • Example URL: /models/categories
    2. Creators and Teams:

      • URL: /[type]/[name] (where type is creators or teams and name is the url slug).
      • Behavior: Returns the specific creator or team object, including a page boolean indicating if the URL was valid.
      • Example URL: /creators/my-awesome-creator
    3. Individual Assets:

      • URL: /[assetType]/[name] (where name is the asset's unique identifier).
      • Behavior: Returns the asset details. If the asset has an approved predecessor or successor (based on ID sequence), they are included in the response under the keys prev and next respectively.
      • Example URL: /models/my-3d-model-id
  10. Generate HDRI scene boilerplate with createCode

    main

    The createCode utility generates a complete boilerplate for a Three.js scene configured to use an HDRI (High Dynamic Range Image) for environment lighting and background. It produces an array containing common Three.js setup code and a specific src/index.js file.

    Key features of the generated code:

    • Uses RGBELoader to load an equirectangular HDRI file.
    • Uses PMREMGenerator to convert the HDRI into a Pre-filtered Mipmapped Radiance Environment Map (PMREM) for realistic lighting.
    • Sets scene.background and scene.environment to the processed environment map.
    • Configures renderer.toneMapping to THREE.ACESFilmicToneMapping for high-quality color rendering.
    • Includes a sample reflective sphere to demonstrate the lighting effect.
    import { createCode } from './path/to/this/module';
    
    const hdriConfig = { file: 'path/to/your/environment.hdr' };
    const generatedFiles = createCode(hdriConfig);
    
    // generatedFiles contains an array of objects with { filename, code }
    console.log(generatedFiles);
  11. Use the Nav component

    main

    The Nav component is a layout element used to render the application's main navigation bar. It includes a logo, dropdown menus (via PopOverMenu), primary navigation links, a dark mode toggle, and a user menu. It automatically handles responsive behavior, switching between a desktop horizontal menu and a mobile disclosure-based menu.

    Key features:

    • Responsive Design: Uses @headlessui/react's Disclosure to manage mobile menu visibility.
    • Dark Mode: Integrates with nightwind and a global useStore to toggle between light and dark themes.
    • Dynamic Navigation: Retrieves menu structures (dropdownMenus, navigation, and mobileNav) from the useNav hook.
    • User Context: Displays user-specific information via the UserMenu component.
    import Nav from '@/components/layout/nav'
    
    // Usage within a layout component
    const Layout = ({ children }) => (
      <>
        <Nav />
        <main>{children}</main>
      </>
    )