Here we will use party bears (collectionId 303204 on Porcini) as an example to create schemas, and then equip the party bear dynamically through the schema.

Schema Creation

https://ar-docs.futureverse.dev/schema/

const namespace = "http://schema.futureverse.dev/pb" as NamespaceUrl;

const bearSchema = `
@prefix this: <http://schema.futureverse.dev/pb>.
@prefix sh: <http://www.w3.org/ns/shacl#>.
@prefix fvp: <http://schema.futureverse.com/#>.
@prefix path: <http://schema.futureverse.com/path#>.

this:Bear a fvp:OnChainERC721Asset;
    sh:property [
  sh:minCount 0;
  sh:maxCount 1;
  sh:class this:AccessoryEars;
  sh:path path:equippedWith_accessoryEars
], [
  sh:minCount 0;
  sh:maxCount 1;
  sh:class this:AccessoryEyewear;
  sh:path path:equippedWith_accessoryEyewear
].
`;

const accessoryEyewearSchema = `
@prefix this: <http://schema.futureverse.dev/pb> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix fvp: <http://schema.futureverse.com/#> .
@prefix path: <http://schema.futureverse.com/path#> .

this:AccessoryEyewear a fvp:OnChainERC721Asset ;
.
`;

const accessoryEarsSchema = `
@prefix this: <http://schema.futureverse.dev/pb> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix fvp: <http://schema.futureverse.com/#> .
@prefix path: <http://schema.futureverse.com/path#> .

this:AccessoryEars a fvp:OnChainERC721Asset ;
.
`;

const SchemaCreation = () => {
    const { createAsync: createSchemaAsync } = useCreateSchema();

    const createPartybearSchema = async () => {
        await createSchemaAsync({
            name: "bear",
            schema: bearSchema,
            version: 0,
            namespace,
        });
    };

    const createAccessoryEyewearSchema = async () => {
        await createSchemaAsync({
            name: "accessoryEyewear",
            schema: accessoryEyewearSchema,
            version: 0,
            namespace,
        });
    };

    const createAccessoryEarsSchema = async () => {
        await createSchemaAsync({
            name: "AccessoryEars",
            schema: accessoryEarsSchema,
            version: 0,
            namespace,
        });
    };

    return (
        <div>
            <button onClick={createPartybearSchema}>Create Partybear Schema</button>
            <button onClick={createAccessoryEyewearSchema}>Create AccessoryEyewear Schema</button>
            <button onClick={createAccessoryEarsSchema}>Create AccessoryEars Schema</button>
        </div>
    );
};

Asset Registration with Schema

https://ar-docs.futureverse.dev/collection/

const SchemaRegistration = () => {
  const { createAsync } = useRegisterTokenSchema()
  const register = async (collectionId, schemaId) => {
    await createAsync({
      collectionId,
      schemaId,
    })
  }

  return (
    <div>
      <button
        onClick={() =>
          register('7672:root:303204', 'http://schema.futureverse.dev/pb#bear')
        }
      >
        Register party bear
      </button>
      <button
        onClick={() =>
          register(
            '7672:root:240740',
            'http://schema.futureverse.dev/pb#AccessoryEars',
          )
        }
      >
        Register AccessoryEars
      </button>
      <button
        onClick={() =>
          register(
            '7672:root:245860',
            'http://schema.futureverse.dev/pb#AccessoryEyewear',
          )
        }
      >
        Register AccessoryEyewear
      </button>
    </div>
  )
}

Find equitable slots for the party bear

https://ar-docs.futureverse.dev/manage-assets/QXNzZXQ6NzY3Mjpyb290OjMwMzIwNDoyMzI=

// An component to display all equitable slots for an party bear
const SwappablesRootAsset = ({ address, tokenId, collectionId}) => {
  const { asset } = useGetAsset(
    {
      tokenId, // party bear token id
      collectionId,
      addresses: [address],
    }
  )
  
  const { assets } = useAssets(
    {
      first: 1000,
      addresses: [address],
    }
  )
  
  type Slot = {
    schemaName: string
    assets: typeof assets
  }
  const [accessorySlots, setAccessorySlots] = useState<Slot[]>([])
  useEffect(() => {
    if (!assets || !asset) {
      return
    }
    const updateSlots = async () => {
      const slotSchemaNames = await getPaths(asset?.schema?.schema)
      const schemaNamespace = currentAsset?.schema?.namespace
      const slots = slotSchemaNames.map((schemaName) => {
        const slotAssets = assets.filter(
          (asset) =>
            asset?.schema?.name.toLowerCase() === schemaName.toLowerCase() &&
            asset.schema.namespace === schemaNamespace,
        )
        return {
          assets: slotAssets,
          schemaName,
        }
      })
      setAccessorySlots(slots)
    }
    updateSlots()
  }, [assets, asset])
  
  return <div>display swappable slots for partybear</div>
}

Equip and submit transaction

https://ar-docs.futureverse.dev/manage-assets/QXNzZXQ6NzY3Mjpyb290OjMwMzIwNDoyMzI=

// accessoryEarsAsset is one of the assets selected from last step's slot.assets
const EquipAccessory = (partybearAsset, accessoryEarsAsset) => {
    const { submitAsync, transaction } = useSignAndSubmitTransaction()
    const handleSave = async () => {
    const { data: artm } = await getARTM()
      artm.operations = []
      artm.addOperation({
        type: 'asset-link',
        action: 'create',
        args: [
          `equippedWith_accessoryEars`,
          partybearAsset.assetTree.nodeId,
          accessoryEarsAsset.assetTree.nodeId,
        ],
      })  
      submitAsync({ artm })
    }
    return <button onClick={submitAsync}>save</button>
}