Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/polyhaven-relevance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@refkit/provider-polyhaven': patch
---

Poly Haven results are ranked by how well they match the query, then by popularity. A query word found as a word of an asset's name or id counts most, then a tag or category, then a match inside a longer word; ties go to the most-downloaded asset. Before, most matches tied and kept Poly Haven's alphabetical order, so "sunset HDRI" returned `aarfontein_dawn_2`, `aarfontein_dusk` and the like instead of the popular sunset skies. An empty query now lists the most-downloaded assets first. Query words may be in any script (`crème`, `日落`); a query that matches no asset, including one made only of punctuation, returns nothing.

The asset list (about 1 MB per asset type) is downloaded once and reused for an hour by each provider instance, instead of on every search. Change that with the new `listTtlMs` option; `0` turns the cache off. A shared list download still unfinished after 30 seconds fails the searches waiting on it; if a host allows Poly Haven searches longer than that, `listTtlMs: 0` restores one download per search, bounded only by the host's own timeout.
12 changes: 12 additions & 0 deletions packages/provider-polyhaven/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ const refkit = createRefkit({ providers: [polyhaven(), polyhaven({ assetType: 'h
const hdris = await refkit.search({ query: 'sunset', modalities: ['image'], sources: ['polyhaven-hdri'] })
```

### Ranking

Poly Haven's list endpoint has no search parameter, so `polyhaven()` downloads the whole list and ranks it itself. A word is a run of Unicode letters, combining marks and digits, compared case-insensitively, so `crème` and `日落` are single words. Each query word adds the score of its best match in an asset: 3 if it is a word of the asset's name or id, 2 if it is a tag or category or a word of one (`sunset` in `sunrise-sunset`), 1 if it only appears inside one of those fields. Assets that match no word are dropped. Equal scores go to the most-downloaded asset first. An empty or whitespace-only query returns every asset, most-downloaded first. Any other query that matches nothing returns nothing: that includes a query in a script no asset uses, and one made only of punctuation or emoji. `page` steps through this ranked list in windows of `maxAssets`.

### Asset list cache

The list is about 1 MB, so each provider instance keeps the copy it downloaded for `listTtlMs` milliseconds (default `3_600_000`, one hour) and ranks later searches against it. Searches that run at the same time share one download. A failed download is not kept, and neither is one still unfinished after 30 seconds: its searches fail and the next search starts a new download. Set `listTtlMs` to `0`, a negative number or `NaN` to download the list on every search; `Infinity` keeps the list for as long as the provider instance lives.

```ts
polyhaven({ assetType: 'hdris', listTtlMs: 10 * 60_000 }) // re-download the HDRI list every 10 minutes
```

### ambientCG sibling factory

`ambientcg()` lives in the same package and returns the same CC0-normalized image references, hitting ambientCG's API instead:
Expand Down
Loading
Loading