dsh-reference-frames 1.6.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,105 @@
1
+ # Changelog
2
+
3
+ ## v1.6.1 — 2026-11-09
4
+
5
+ The guide and changelog now ship with the npm package.
6
+
7
+ - **`docs/*.md` and `CHANGELOG.md` are in the tarball.** 1.6.0 shipped the README, whose links point at `docs/GUIDE.md` and `CHANGELOG.md` — both were missing from the package, so those links 404'd for anyone installing from npm. They now travel with the package.
8
+ - Nothing else changes; the plugin code is byte-identical to 1.6.0.
9
+
10
+ ## v1.6.0 — 2026-11-09
11
+
12
+ The plugin is on npm; updates are now Harness's Plugins page.
13
+
14
+ - **Published to npm.** `dsh-reference-frames` installs from the Plugins page, which saves it as an exact version and then lists newer releases with an **Update** button. The clone-and-symlink recipe becomes the development path instead of the only path.
15
+ - **The in-plugin updater is gone.** The `git fetch` check, the round pill left of the tabs, `GET` / `POST /anistyle/update`, `POST /anistyle/restart` and the desktop relaunch helper are removed. The gear menu ends with the version this copy came from, read from the new `GET /anistyle/version`, and nothing in the panel contacts GitHub.
16
+ - **Saved boards moved out of the package.** They live in `~/.dsh/reference-frames/moodboards.json`, seeded on first run from the boards the package ships in `presets/moodboards.json`, so a plugin update no longer overwrites them. The "Sync to GitHub" icon appears only in a git checkout — an npm install has no repo to push to, and saving just writes the local file there (`GET /anistyle/presets` reports `checkout`).
17
+ - **Release automation.** Pushing a `vX.Y.Z` tag runs `.github/workflows/release.yml`: it checks the tag against `package.json`, publishes with npm trusted publishing plus provenance, and opens a GitHub release titled `vX.Y.Z` whose notes are that CHANGELOG section.
18
+
19
+ ## v1.5.1 — 2026-11-09
20
+
21
+ The loading sweep is back in the light theme.
22
+
23
+ - **Skeleton cards shimmer again in light mode.** Both `--dsw-alias-bg-layer-1` and `--dsw-alias-bg-layer-2` resolve to `#fff` in the light theme, so the skeleton gradient collapsed into three identical stops and the sweep was invisible while a search was running; the dark theme, where the two layers differ, was unaffected. The light theme now builds its highlight from `label-primary` at 4% — a soft `#f5f5f5` band, matched to the contrast the dark theme always had — and the dark theme keeps its original `layer-1` band behind `[data-ds-dark-theme]`, so it looks exactly as before.
24
+ - The busy sweep shown while a frame is being added hard-coded `rgba(255,255,255,.14)`, which was equally invisible on white. It now uses `label-primary` at 14% — the same white in the dark theme, a visible sweep in the light one.
25
+
26
+ ## v1.5.0 — 2026-11-07
27
+
28
+ FrameThrower is now three selectable reference sources, and the lightbox picks a moodboard on hover.
29
+
30
+ - **Film stills and commercial shots are independent sources.** The Sources picker groups Animation frames, Film stills and Commercial shots under FrameThrower; the three switches are independent and use the existing `ft_…` token. Film calls `POST /search`; commercial shots call `POST /commercials/shots/search`. Both are **off on first run**, so the default search stays one request at the old cost — turn them on under Sources.
31
+ - Film and commercial results are normalized into the existing tile shape: title / brand, year, caption, shot tags, palette and link. Film tiles carry a “Film” badge, commercial shots “Ad”, and the markdown export names the library.
32
+ - Similar frames (≈) now works per library: `/similar` for film and `/commercials/shots/similar` for commercial. A mixed moodboard asks each library once and interleaves the answers. Attached-image search covers the animation and commercial libraries; film is skipped because `/search/image` only accepts a publicly reachable image URL, and the grid explains the skip.
33
+ - Paging is per source with each endpoint's offset cap; a source whose first page is empty is not paged again, so a quiet library does not spend credits on every “Browse more”. The host cache is keyed per source.
34
+ - Settings keeps one FrameThrower card — one token field — whose switch turns the whole animation / film / commercial family on or off; the per-library switches stay in the composer. The settings card enters the token once for all three.
35
+ - `/anistyle/frames` and `/anistyle/similar` gain a `source` field (`animation`, `film`, `commercial`); responses keep `source: "framethrower"` and each frame now carries `kind`. Normalization also reads camelCase film metadata and flat or nested commercial fields (brand, spot, still, palette).
36
+ - **The lightbox picks a board on hover.** Hovering 「+ 加入情绪板」 unfolds the board list instead of opening the modal: each board shows its frame count and a ✓ when this frame is already in it, and one click adds the frame — the lightbox stays open, so the next image is one arrow key away. The foot of the list creates a board inline. Opened from inside a board, the button still adds straight to that board.
37
+
38
+ ## v1.4.1 — 2026-11-06
39
+
40
+ Web image search works again, and the Discover top bar drops its brand line.
41
+
42
+ - Bing's `/images/async` fragment — the fallback added in 1.4.0 — now answers a plain request with a script-only stub and no result markup, so every query parsed to zero frames while the panel said 「没有返回图片」. The web source reads Bing's full server-rendered `/images/search` page again (still no key, still every language), and DuckDuckGo stays as the fallback for when Bing shows a human check. The Bing page is parsed with the same `iusc` markup as before, now tolerant of extra classes on the tile.
43
+ - A Bing human-check page is reported as a rate-limit hint instead of looking like "this query has no images".
44
+ - The image proxy sniffs the first bytes when a host labels a real image as `application/octet-stream` (naruto-official.com does this with its webp art), so those tiles no longer leave holes in the grid; anything that is not actually an image still gets a 415.
45
+ - The Discover top bar no longer repeats the plugin name: the dot + “Reference Frames” line is gone and the Discover / Moodboards tabs sit flush right, so the page starts with the results.
46
+
47
+ ## v1.4.0 — 2026-11-06
48
+
49
+ Updates land from the panel with a single click, next to a round of search and copy fixes.
50
+
51
+ - AI interpretation is now language-agnostic. The helper prompt detects the brief's language and translates its meaning into English FrameThrower queries, while keeping web search phrases in the brief's language (Chinese, Japanese, Korean, French, Spanish and others). The client no longer assumes Chinese when deciding whether a brief needs AI — non-Latin scripts and accented Latin text are recognised — and web search picks its market from the query script instead of the panel UI. The “needs AI” copy now says “non-English” rather than “Chinese”.
52
+ - Web image search now starts with DuckDuckGo's Bing-backed image endpoint for every language, with direct Bing as a fallback. This fixes the empty 「网页图片 · 没有返回图片」 warning caused by Bing's bot-challenge page (and its habit of mapping names such as 「奶龙」 to unrelated homophones). A partial empty now reads 「部分检索词没有返回图片」 instead of claiming the whole source returned nothing.
53
+ - Author metadata is now declared: `package.json` gains `author` and a `contributors` entry for [DeepSeek](https://github.com/deepseek-ai).
54
+ - The Chinese README moved to `docs/README.zh-CN.md`; the language switcher in both readmes points at the new path, and its guide / changelog links are now relative to `docs/`.
55
+ - A **「清空」/ Clear** button now sits to the left of 「换一批」 in the results header. One click — no confirmation, no toast — clears the visible reference frames, the persisted view cache (so a reload stays empty) and the host-side frame / web / image / interpret / vocabulary caches, so the next search or reshuffle starts fresh. Adds `POST /anistyle/clear-cache`. An in-flight request can no longer repopulate a grid that was just cleared. The emptied grid keeps a quiet placeholder — a stacked-frame mark with a one-line prompt — so the page never reads as a blank middle. The placeholder fills the scrollport exactly, so it does not introduce a stray scrollbar.
56
+ - **One-click updates in the panel.** The plugin is a git checkout, so the panel compares local `HEAD` with `origin/main` on load — a quiet `git fetch`, cached for 10 minutes host-side — and shows a round brand-blue button with a downward arrow left of the Discover / Moodboards tabs when the branch has moved; hovering it reads 「检测到新版本」. One click fast-forwards (`git merge --ff-only`, so uncommitted local edits are never touched and history is never rewritten) and the button turns into a spinner. A client-only change reloads the page; a change to host files makes the host relaunch the desktop app (quit, then reopen by bundle id) so both halves boot from the new checkout — no confirmation dialog on this path. If a task or an armed reminder is running, the app is left alone and the button becomes 「重启生效」 until the work finishes. In a plain browser the app is never quit; a toast asks for a manual restart instead. Offline, a merge blocked by local changes and a diverged branch are reported in a toast. Settings ends with the current version and a 「检查更新」 action. Adds `GET /anistyle/update`, `POST /anistyle/update` and `POST /anistyle/restart`.
57
+
58
+ ## v1.3.2 — 2026-11-06
59
+
60
+ Image input now reaches the web source, and the attached image has a real preview.
61
+
62
+ - Upstream warnings now name their source, e.g. `FrameThrower · No animation title called “Arcane”.`, so a note from one source is never mistaken for the other's.
63
+ - The pasted / dropped image now actually renders in the composer: the thumbnail was pointing at the attachment object instead of its `preview` data URL. The attachment is a square thumbnail with a circular × that only appears on hover, matching the host chat composer — no caption or "remove" text, no focus ring from clicking it.
64
+ - Clicking the attached thumbnail (cursor: zoom-in) opens the image in a full-screen lightbox; close it with ×, a click outside, or Escape.
65
+ - Right-click (or two-finger click on a trackpad) an enlarged image — in the attachment preview or the frame lightbox — to get a small **Copy image** menu. The image is normalized to a PNG (longest side capped at 2400px) and written through the Clipboard API; a toast confirms success or explains a failure, including unsupported browsers.
66
+ - **Image search now reaches the web source.** With Chrome web images enabled, the default vision model reads the attached image and turns it into Bing search phrases; FrameThrower still gets the raw image for its native visual similarity. Both result sets are interleaved when both sources are on. With AI off, a typed note is used as the web query and an empty note explains why the image cannot be translated. Adds `POST /anistyle/interpret-image`; the image is admitted through the host attachment store so it can be sent as a real image block.
67
+
68
+ ## v1.3.1 — 2026-11-05
69
+
70
+ Housekeeping.
71
+
72
+ - Remove the unused `styles.json` catalog and its legacy `GET /anistyle/library` route; style keywords keep coming from FrameThrower's `/animation/vocabulary`.
73
+
74
+ ## v1.3.0 — 2026-11-05
75
+
76
+ Multiple retrieval sources, and a source the user can switch per search.
77
+
78
+ - **AI directions** — the AI switch takes x1 / x2 / x3 and asks the model for that many distinct readings of the brief, interleaving their pages instead of searching one description.
79
+ - **Community boards** — the preset button now opens a browser with cover previews and per-board install (the old button installed everything at once).
80
+ - **Language switch** — 简体中文 / English directly in Settings.
81
+ - **Inline keyword management** — add, rename and delete terms and categories from the keyword panel; a new term commits on blur or Enter.
82
+ - **Sources picker** in the composer (next to Keywords); Settings keeps the token fields and switches only for token-based sources. Everything that is on joins the search; a source that is off (or has no token) is skipped, and a source that fails only adds a warning line — the other source's results still show.
83
+ - **Chrome web images**: a second source backed by Bing image search. No token, Chinese briefs work as-is, paging via “Browse more”. Results carry a “Web” badge, open the source page, and are interleaved + de-duplicated with FrameThrower frames.
84
+ - **Faster AI helper calls**: the interpret step now asks for the model's cheapest reasoning level, reserves enough output tokens for reasoning + JSON (1200), and allows 15s, so a thinking default no longer trips the old 8s cap. A provider whose `reasoningEfforts.off` maps to nothing can still think for 10s+; mapping it to `off` makes the helper return in ~2s.
85
+ - **AI search feeds both sources**: one model call now returns English frame descriptions for FrameThrower *and* 2–3 short image-search phrases for the web source (keywords, not sentences; Chinese or official English names allowed). The AI switch also appears when only the web source is on, and the web source falls back to the raw brief when AI is off or the call fails.
86
+ - **Preset sync moved to the moodboards header**: the “save as plugin preset” row is gone from Settings. A small upload icon now sits left of “Community boards”, shows a spinner while saving, and hints “Sync to GitHub” on hover.
87
+ - **Clean web card text**: Bing wraps matched terms in private-use highlight markers (U+E000/U+E001), which rendered as tofu/⏸ blocks. They are stripped at parse time and again at render time, so frames already saved in moodboards clean up on refresh; results with no Bing title fall back to the source domain, and the redundant “web” tag chip is gone.
88
+ - Images from the web source are fetched through a local `/anistyle/img` proxy (cached, private hosts rejected, type/size checked) so hotlink protection and http-only hosts no longer leave holes in the grid.
89
+ - Source-aware UI: the ↗ tooltip and lightbox link no longer say “FrameThrower”; similarity (≈) and image search stay FrameThrower-only and hide on web tiles. Markdown export writes each frame's original image URL and source.
90
+ - Without a token the plugin still works: enable only the web source, or leave both on — FrameThrower is skipped until a token is saved.
91
+ - **Pinterest is not integrated**; the reasoning (partner-only search, ToS) is documented in the guide.
92
+
93
+ ## v1.2.0 — 2026-11-05
94
+
95
+ First public release.
96
+
97
+ - Prompt-first discovery: type a feeling in Chinese or English, or drop / paste an image; the panel decides which path to take.
98
+ - **AI search** switch in the composer: the host's default model turns the brief into one English single-frame description (with optional title / genre / per-title in the margin). Off means the words go upstream untouched; a Chinese brief then stops at “AI search needed” instead of showing the upstream default page.
99
+ - Honest results: the grid is cleared on every search, the exact query is always shown, and failures (no token, credits, rate limit, upstream status) are stated instead of padded with stale frames.
100
+ - Keywords as editable chips grouped by category, inserted into the brief rather than fired as a search; categories, terms and renames are all user-managed and stored locally.
101
+ - Moodboards: create / rename / delete / pin, hover-only card actions, per-frame add picker that stays open for multi-board adds, Markdown export.
102
+ - Per-card ≈ swaps just that tile with a visually similar frame; inside a board ≈ returns recommendations you can accept one by one, and “Similar picks” samples three random frames as one multi-image reference.
103
+ - Lightbox with ← → navigation and an add-to-board action that knows which board you are in.
104
+ - “Browse more” appends the next page, de-duplicates, survives reloads, and says “no more” instead of going silent.
105
+ - Optional preset moodboards: `presets/moodboards.json` ships nothing by default; a user can install the author's boards with one click, and the author saves + auto-pushes them from the settings panel using local git credentials.
package/docs/GUIDE.md ADDED
@@ -0,0 +1,119 @@
1
+ # Guide
2
+
3
+ [English](GUIDE.md) · [简体中文](GUIDE.zh-CN.md)
4
+
5
+ ## Search
6
+
7
+ One input box. Type a brief, or paste / drag / pick an image — the panel decides: text becomes a frame search; an image goes to FrameThrower as a visual-similarity search and, when the web source is on, through the vision model into web image keywords.
8
+
9
+ - **AI search** (switch in the composer, left of the search button; used by every source, and shown even when only the web source is on):
10
+ - On — the host's default model returns two things in one call: one English single-frame description for the FrameThrower libraries (title / genre / per-title filters apply to the animation library), and 2–3 short image-search phrases for the web source (keywords, not sentences; they may stay in the brief's language or use an official English name). The model detects the brief's language first and translates the meaning into English for FrameThrower; Chinese, Japanese, Korean, French, Spanish and other languages can be typed directly. The exact terms are shown per source above the grid. With an attached image, a separate vision call reads the image (using your note as context) and produces the web phrases; FrameThrower still gets the raw image.
11
+ - Off — your words go upstream untouched: FrameThrower needs English, the web source takes the brief as written. For an attached image, no vision call happens: the web source uses your typed note as its query, and explains that the image itself cannot be translated when the note is empty.
12
+ - The helper asks for the model's lowest thinking level. A thinking model whose provider maps `reasoningEfforts.off` to nothing will still think for 10s+; mapping it to `off: off` makes the call return in ~2s, otherwise it times out and falls back to the raw brief.
13
+ - **Non-English briefs and image-based web search need AI.** FrameThrower matches English descriptions; a brief in Chinese, Japanese, French or any other language falls back to the default page. The AI step detects the input language and translates the meaning into English queries while keeping web phrases in the brief's language. Web image search needs a vision-capable model to turn an attached image into queries. With AI off the panel says so instead of sending a placeholder request.
14
+ - **Results always belong to the current search.** The grid is cleared first, the query is always visible, and failures (no token, credits, rate limit, unreachable, upstream status) are stated plainly.
15
+ - **Browse more** appends and de-duplicates the next page; “More frames” replaces the set instead. At the end it says “no more frames”; a failed page keeps the button and shows why.
16
+ - **Clear** sits left of “More frames” in the results header. One click — no confirmation, no toast — empties the grid, drops the persisted view cache (so a reload stays empty) and wipes the host-side search / image / interpret caches, so the next search starts fresh. The emptied grid keeps a quiet placeholder instead of leaving the middle blank.
17
+
18
+ ## Sources
19
+
20
+ “Sources” sits in the composer toolbar next to “Keywords”. Clicking it opens per-source switches. The three FrameThrower libraries sit together under one group; the web source sits below them. Settings shows one token card, entered once, and its switch turns the whole FrameThrower family on or off. The choice lives in `anistyle:sources:v1`. A search only calls the sources that are on, and one source failing never hides the others' results — the reason is listed above the grid.
21
+
22
+ - **Animation frames** — animated series and films matched against English single-frame descriptions; needs a token; supports similar frames, image search and reshuffling.
23
+ - **Film stills** — live-action frames from FrameThrower's film library (`POST /search`); needs a token. Supports similar frames and reshuffling, but not image search: that endpoint only accepts a publicly reachable image URL, so an attached image is skipped with a note.
24
+ - **Commercial shots** — individual shots from ads (`POST /commercials/shots/search`), tagged with brand, spot, year, shot size and light; needs a token. Supports similar shots and image search.
25
+ - **Chrome web images** — Bing Images' server-rendered result page for every language, with DuckDuckGo Images as a fallback. No token. With AI on it searches the model's short phrases, and falls back to your wording when AI is off or fails. Attach an image and the vision model reads it first, then searches with the phrases it describes (AI off means the image cannot be translated — a typed note is used as the query instead). No similar frames. These are public web endpoints, not official APIs: they can throttle, answer a scripted request with a human check, break on redesign, or return dead image links. Images go through the local `/anistyle/img` proxy to dodge hotlink protection and mixed content.
26
+ - **Where a tile came from** — web tiles carry a “Web” badge, film tiles “Film” and commercial shots “Ad”; ↗ opens the source page. Results from every enabled source are interleaved and de-duplicated.
27
+ - Similar (≈) appears on every FrameThrower tile (animation, film and commercials). An attached image goes to the animation and commercial libraries as a visual-similarity search, and to the web source through the vision model; film stills are skipped because their API needs a public image URL. With several sources on, the result sets are interleaved.
28
+ - Film and commercials are **off on first run** so the default search stays one request at the old cost; turn them on under Sources. The animation / film / commercial switches are independent.
29
+ ### Why not Pinterest
30
+
31
+ Pinterest's only public keyword search is `GET /v5/search/partner/pins`: a closed beta for invited/approved partners, capped at the top 10 results; `GET /v5/search/pins` only searches your own account's Pins. Access requires a business account, application review (Trial is rate-limited per day and tokens expire in 24h), Standard access, and OAuth 2. Pinterest's ToS also forbids automated scraping without permission. So this release does not integrate Pinterest; the only viable routes are partner + official API, or letting users paste board links themselves.
32
+
33
+ ## Keywords
34
+
35
+ “Keywords” under the input opens chips grouped by category (era, rendering, lighting …).
36
+
37
+ - Clicking a chip inserts it into the brief — it does not search. Click again to remove it.
38
+ - Manage mode: rename or delete a term, add a term, rename a category, add a category, delete a category. Built-in categories come back with “restore defaults”.
39
+ - Everything is stored locally in `anistyle:keywords:v1`.
40
+
41
+ ## Frames
42
+
43
+ Each frame shows title / year, its caption, shot tags and its own palette. Three buttons appear on hover:
44
+
45
+ | Button | Action |
46
+ | --- | --- |
47
+ | + | Open the board picker. Click a board to add it — the picker stays open for more boards; the trailing + takes a name and creates a board on the spot |
48
+ | ≈ | Replace **this tile only** with a visually similar frame (FrameThrower tiles only) |
49
+ | ↗ | Open the frame's source page |
50
+
51
+ Click an image to open the lightbox: `←` `→` to move, `Esc` to close, and **+ Add to board** at the right end of the caption row. Hover that button to unfold your boards; click one to add the frame and the lightbox stays open, ready for the next image. The bottom of the list creates a board on the spot. Opened from inside a board, the button reads **Add to this board** and drops the frame straight in. Right-click (or two-finger click on a trackpad) an image in either the frame lightbox or the attached-image preview to get a **Copy image** menu: it writes a PNG to the system clipboard, scaling down past 2400px, and says so explicitly when the browser cannot copy images.
52
+
53
+ ## Moodboards
54
+
55
+ Boards start empty and are stored in this browser.
56
+
57
+ - Card actions appear on hover: pin ↑ (pinned boards sort first) and delete ×.
58
+ - Inside a board, ≈ on a frame returns recommendations in a strip above the grid. Click + on a recommendation to add it; nothing is added otherwise.
59
+ - **Similar picks** (board header) samples three random frames from the board and searches with all of them at once. “Reshuffle” samples again.
60
+ - Rename, remove frames, and export Markdown (per-frame caption, palette, deep link).
61
+
62
+ ## Preset moodboards
63
+
64
+ Your boards are saved to `~/.dsh/reference-frames/moodboards.json` — outside the installed package, so a plugin update never overwrites them. The first run seeds that file from the boards the package ships in `presets/moodboards.json`.
65
+
66
+ - Users: when the package's file has content, a **Community boards** button appears on the moodboards page. Same-name boards are skipped and ids are regenerated; ignoring the button changes nothing.
67
+ - Author: in a checkout, the upload icon at the right of the moodboards header (tooltip “Sync to GitHub”) writes the current boards back into `presets/moodboards.json`, then commits and pushes with your local git credentials; the icon spins while it runs. An npm install has no repo to push into, so the icon is hidden there and saving just writes the local file.
68
+
69
+ ```yaml
70
+ # cordis.patch.yml
71
+ config:
72
+ autoPush: true # false = write the file only
73
+ pushRemote: origin
74
+ pushBranch: main
75
+ ```
76
+
77
+ ## Updates
78
+
79
+ Updates belong to Harness's **Plugins** page: the plugin is published on npm, and its bundle page lists newer versions with an **Update** button that replaces the installed copy in place. Nothing inside the panel talks to GitHub.
80
+
81
+ - Install from npm (Plugins page → 添加插件) and the version list appears on its own; a `link:` checkout gets no list, so update that with `git pull` and a restart.
82
+ - The gear menu ends with the version this copy came from — a label, no button.
83
+
84
+ ## Token & cost
85
+
86
+ Gear menu → paste the `ft_…` token. It stays in browser localStorage, travels as a request header to the local route, and is forwarded host-side; it never enters the chat or the bundle. The token only affects FrameThrower; the web-image source needs none.
87
+
88
+ Animation frames cost about 4 credits per search, film stills and commercial shots about 2. A similar-frame search costs 2, or 10 when searching by image.
89
+
90
+ ## Files & routes
91
+
92
+ | File | Role |
93
+ | --- | --- |
94
+ | `index.js` | Host half: proxies the three FrameThrower libraries (animation / film / commercials) and web images (DuckDuckGo / Bing fallback), image proxy, caches searches per source, caches the style vocabulary for 24h, rewrites the brief and reads attached images for web queries with the default model, reads/writes presets |
95
+ | `client.js` | Browser half: panel UI, source switches, AI switch, moodboards in localStorage |
96
+ | `cordis.patch.yml` | Plugin row and config |
97
+ | `presets/moodboards.json` | Shared moodboards shipped with the package (the live copy is `~/.dsh/reference-frames/moodboards.json`) |
98
+ | `locale/*.json` | Title and description shown in the plugin manager |
99
+
100
+ - `POST /anistyle/interpret` — `{ text }` → `{ source: 'model'|'none', params }`
101
+ - `POST /anistyle/interpret-image` — `{ image, text?, count? }` → `{ source: 'model'|'none', params: { web } }` (vision model; stores the image as a host attachment)
102
+ - `GET /anistyle/vocabulary` — style vocabulary (proxied and cached)
103
+ - `POST /anistyle/frames` — `{ source?: 'animation' | 'film' | 'commercial', query, limit, offset, ... }`; animation also takes `style` / `title` / `genre` / `perTitle`, film `film_title` / `genre`, commercial `perSpot`
104
+ - `POST /anistyle/web` — `{ query, limit, offset }` → `{ source: 'chrome', frames }` (market inferred from the query script)
105
+ - `GET /anistyle/img?u=` — image proxy (same-origin, cached, private hosts rejected, size/type limited)
106
+ - `POST /anistyle/similar` — `{ source?, frameId | frameIds | image, by?, limit }` (film needs ids; commercial maps ids to shots and an image to `/commercials/shots/image`)
107
+ - `GET /anistyle/presets` — `{ boards, checkout }`; `checkout` says whether this install can push boards back to the repo
108
+ - `POST /anistyle/presets` — write the boards to the user's data file; pushes only from a checkout
109
+ - `POST /anistyle/clear-cache` — clear all in-memory caches (frame / web / image / interpret / vocabulary)
110
+ - `GET /anistyle/last` — last upstream response (diagnostics)
111
+ - `GET /anistyle/version` — the installed version, shown at the foot of the gear menu
112
+
113
+ ## Maintenance
114
+
115
+ - Two ways in: the npm copy under `~/.dsh/profiles/<profile>/node_modules/dsh-reference-frames` (what users run), or a `link:`ed checkout for development.
116
+ - In a checkout: `client.js` → refresh the page; `index.js` / `cordis.patch.yml` → restart the app. In an npm install, edit the checkout and publish — the change arrives through the Plugins page.
117
+ - Check syntax with `node --check client.js && node --check index.js`.
118
+ - Renaming requires four matching values: package `name`, `cordis.patch.yml` `name`, `client.js` `id`, and the profile entries.
119
+ - Release: bump `package.json`, add a `CHANGELOG.md` entry, commit, then push a `vX.Y.Z` tag. `.github/workflows/release.yml` publishes to npm (trusted publishing, no OTP) and opens the GitHub release titled `vX.Y.Z`.
@@ -0,0 +1,120 @@
1
+ # 使用与维护
2
+
3
+ [English](GUIDE.md) · [简体中文](GUIDE.zh-CN.md)
4
+
5
+ ## 检索
6
+
7
+ 只有一个输入框。可以写一句需求,也可以粘贴 / 拖入 / 选择一张图——面板自己判断:文字走帧检索;有图时动画库和广告库按图找相似帧,网页源开着则先让多模态模型读图、生成网页检索词。
8
+
9
+ - **AI检索**(输入框内、搜索按钮左侧的开关,所有源都用;只开网页源时也会出现):
10
+ - 开——宿主用默认模型一次给出两组词:FrameThrower 三个库共用的英文「单帧画面描述」(作品名 / 类型 / 每部取几张只供动画库),以及网页图片用的 2-3 条短检索词(关键词而不是句子,可以保留原文语言或官方英文名)。模型会先识别输入语言,再把内容翻译成英文供 FrameThrower 使用;中文、日文、韩文、法文、西班牙文等都可以直接输入。结果区上方按源逐行显示实际发出的词。贴图时会另起一次多模态调用读图(输入的文字作为补充语境)生成网页检索词;FrameThrower 仍然直接拿原图找相似帧。
11
+ - 关——原文直接发给各源:FrameThrower 需要英文,网页图片则是你写的原话。贴图时不会调用模型:网页源改用你输入的文字检索;没有文字时直接说明图片无法转成检索词。
12
+ - 选的是模型的「最低思考档」。如果默认模型是思考型、且 provider 里 `reasoningEfforts.off` 映射为空,它仍会先思考十几秒;把该映射改成 `off: off` 后,生词约 2 秒返回,否则会超时并退回原文。
13
+ - **非英文需求和网页以图检索都需要 AI。** FrameThrower 按英文描述匹配;中文、日文、法文等任何非英文原文都会退回默认结果。AI 会先识别输入语言,把语义翻译成英文检索词,同时让网页检索词保持原文语言。网页源要把图片变成检索词,必须有能读图的多模态模型。关着 AI 时面板会直接说明,不发占位请求。
14
+ - **结果永远属于这一次检索。** 每次先清空网格,检索词始终可见;失败时直接说明原因(无 token / 额度 / 限流 / 连不上 / 上游状态码)。
15
+ - **浏览更多**追加下一页并去重,「换一批」则是换一组。翻到底显示「没有更多了」;某一页失败会保留按钮并说明原因。
16
+ - 结果区标题右侧、「换一批」左边有「**清空**」:点一下即可(没有确认框、没有提示),清空当前参考帧、浏览器里保存的结果缓存(刷新也不会恢复),以及宿主侧的检索 / 图片 / 改写缓存,让下一次检索从零开始。清空后结果区留有一段克制的占位提示,中间不会变成一片空白。
17
+
18
+ ## 检索源
19
+
20
+ 「检索源」在输入框工具栏、关键词右侧,点开可以逐个开关;三个 FrameThrower 库同属一组,网页源在下面单独一组。状态存在本机 `anistyle:sources:v1`。设置里按凭据只放一张卡:token 填一次,卡片上的开关会同时开关动画 / 电影 / 广告三个库。每次检索只打开发着的源,一个源失败不会挡住其他源的结果,失败原因会作为一行提示列在结果上方。
21
+
22
+ - **动画帧** — 动画剧集与动画电影,按英文单帧描述匹配,需要 token;支持相似帧、按图检索、换一批。
23
+ - **电影剧照** — FrameThrower 真人电影库(`POST /search`),需要 token;支持相似帧和换一批,但不支持按图检索:该接口只收公开可访问的图片 URL,贴图时会跳过并说明原因。
24
+ - **广告镜头** — 广告里的单个镜头(`POST /commercials/shots/search`),带品牌、片名、年份、景别和光线标签;需要 token;支持相似镜头和按图检索。
25
+ - **Chrome 网页图片** — 所有语言都读 Bing 图片的完整结果页,DuckDuckGo 图片兜底;不需要 token。开 AI 时用模型给的短检索词,关 AI 或模型失败时退回原文;没有相似帧。贴图时先让多模态模型读图、生成网页检索词再搜;关掉 AI 时图片无法转成检索词,只会拿你输入的文字去搜。这些都是网页端公开结果,属于非官方接口:可能限流、对脚本请求回人机验证、改版失效,图片也可能 404。图片统一经本机 `/anistyle/img` 代理,避免防盗链和混合内容。
26
+ - **结果的来源** — 网页帧卡片标「网页」,电影标「电影」,广告镜头标「广告」,↗ 打开原始页面;所有开着的结果交替混排并去重。
27
+ - 相似帧(≈)对动画、电影、广告三种 FrameThrower 帧都可用。贴图会同时走多条路:动画库和广告库做视觉相似帧,网页源用多模态模型把图片转成检索词再搜网页图片;电影剧照因为接口只收公开图片链接而跳过。多个源都开时结果交替混排。
28
+ - 电影和广告默认**关闭**,第一次用时在「检索源」里打开;这样默认检索仍是原来的一次请求、原价。三个库的开关彼此独立。
29
+
30
+ ### 为什么没有 Pinterest
31
+
32
+ Pinterest 官方 API 的公开关键词搜索只有 `GET /v5/search/partner/pins`,属于 closed beta,只对受邀/申请通过的 partner 开放,且只回前 10 条;`GET /v5/search/pins` 只能搜自己账号的 Pin。接入还要商业账号 + 应用审核(Trial 按天限流、token 24 小时过期)→ Standard access,以及 OAuth 2 授权。同时 Pinterest ToS 明确禁止未经许可的自动化抓取。所以这一版不接 Pinterest;要做只能走「申请 partner + 官方 API」或「用户主动粘贴板链接」。
33
+
34
+ ## 关键词
35
+
36
+ 输入框下方的「关键词」展开是按类别分组的词(年代、渲染、光线……)。
37
+
38
+ - 点词是**写进需求**,不会触发检索;再点一次取消。
39
+ - 管理模式:改词名、删词、加词、改类别名、新建类别、删除类别。内置类别可用「恢复默认」找回。
40
+ - 全部存在本机 `anistyle:keywords:v1`。
41
+
42
+ ## 帧
43
+
44
+ 每帧显示作品 / 年份、画面描述、镜头标签和它自己的色板。悬停出现三个按钮:
45
+
46
+ | 按钮 | 作用 |
47
+ | --- | --- |
48
+ | + | 打开选板器。点一个板就加入,选板器不会关,可以连续加;末尾的 + 现场输名字新建 |
49
+ | ≈ | 只把**这一张**换成视觉上相似的帧,其他帧不动(仅 FrameThrower 帧) |
50
+ | ↗ | 打开这一帧所在的来源页 |
51
+
52
+ 点图片进入灯箱:`←` `→` 翻页,`Esc` 关闭,说明行右端有「+ 加入情绪板」。悬停这个按钮会展开情绪板列表,点一个就加入,灯箱不关,可以接着翻下一张;列表底部可以现场新建一个板。从情绪板里打开的灯箱,按钮变成「加入这个情绪板」,直接加进当前板。在图片上点右键或触控板双指点按,会弹出「复制图片」菜单:把当前图转成 PNG 写进系统剪贴板,超过 2400px 会等比缩小;浏览器不支持 Clipboard 图片写入时会明确提示。
53
+
54
+ ## 情绪板
55
+
56
+ 情绪板从空开始,存在本机浏览器。
57
+
58
+ - 卡片悬停出现:置顶 ↑(置顶排最前)、删除 ×。
59
+ - 进入情绪板后,帧上的 ≈ 会在网格上方给出「相似推荐」,点 + 才加入,不点什么都不发生。
60
+ - 板头「相似推荐」从板里随机抽 3 帧作为一次多图参考,「换一组」重新抽样。
61
+ - 支持重命名、移除帧、导出 Markdown(逐帧描述、色板、deep link)。
62
+
63
+ ## 预设情绪板
64
+
65
+ 你自己的情绪板保存在 `~/.dsh/reference-frames/moodboards.json` —— 在安装目录之外,插件更新不会覆盖它。首次运行会从包内 `presets/moodboards.json` 播种。
66
+
67
+ - 用户:包内预设文件有内容时,情绪板页会出现「社区情绪板」。同名跳过、id 重新生成;不点则完全不受影响。
68
+ - 作者:在 git 检出里,情绪板页右上角的上传图标(悬停提示「同步至 GitHub」)会把当前情绪板写回 `presets/moodboards.json`,默认用本机 git 凭据提交并推送,上传过程中图标变成转圈。npm 安装没有可推送的仓库,这个图标会隐藏,保存只写本地文件。
69
+
70
+ ```yaml
71
+ # cordis.patch.yml
72
+ config:
73
+ autoPush: true # false = 只写文件
74
+ pushRemote: origin
75
+ pushBranch: main
76
+ ```
77
+
78
+ ## 版本更新
79
+
80
+ 更新交给 Harness 的 **插件** 页:插件发布在 npm 上,bundle 详情页会列出更新的版本,点 **更新** 就地替换已装的副本。面板本身不再联系 GitHub。
81
+
82
+ - 从 npm 安装(插件页 → 添加插件)后版本列表自然出现;`link:` 链接安装不会显示版本列表,那种装法改完 `git pull` 再重启。
83
+ - 齿轮菜单最底下一行只显示当前版本号,没有按钮。
84
+
85
+ ## Token 与费用
86
+
87
+ 齿轮菜单里粘贴 `ft_…`。token 只存在浏览器 localStorage,随请求头发给本机路由,由宿主转发;不进对话,也不进打包产物。token 只影响 FrameThrower 源;网页图片源不需要 token。
88
+
89
+ 动画帧检索约 4 credits,电影 / 广告检索约 2 credits;相似帧检索 2 credits(以图检索 10)。
90
+
91
+ ## 文件与路由
92
+
93
+ | 文件 | 作用 |
94
+ | --- | --- |
95
+ | `index.js` | 宿主半:代理 FrameThrower 三个库(动画 / 电影 / 广告)、网页图片(DuckDuckGo / Bing 兜底)与图片代理、按源缓存检索、缓存 24h 画风词表、用默认模型改写需求、读图生成网页检索词、读写预设 |
96
+ | `client.js` | 浏览器半:面板 UI、检索源开关、AI 开关、情绪板(localStorage) |
97
+ | `cordis.patch.yml` | 插件行与配置 |
98
+ | `presets/moodboards.json` | 随包发布的分享情绪板(实际使用的一份在 `~/.dsh/reference-frames/moodboards.json`) |
99
+ | `locale/*.json` | 插件管理页显示的标题与描述 |
100
+
101
+ - `POST /anistyle/interpret` — `{ text }` → `{ source: 'model'|'none', params }`
102
+ - `POST /anistyle/interpret-image` — `{ image, text?, count? }` → `{ source: 'model'|'none', params: { web } }`(多模态模型;图片会先存入宿主附件库)
103
+ - `GET /anistyle/vocabulary` — 画风词表(转发并缓存)
104
+ - `POST /anistyle/frames` — `{ source?: 'animation' | 'film' | 'commercial', query, limit, offset, ... }`;动画另有 `style` / `title` / `genre` / `perTitle`,电影用 `film_title` / `genre`,广告用 `perSpot`
105
+ - `POST /anistyle/web` — `{ query, limit, offset }` → `{ source: 'chrome', frames }`(检索市场按查询文本的语种判断)
106
+ - `GET /anistyle/img?u=` — 图片代理(同源、带缓存、拒绝内网地址、限制大小与类型)
107
+ - `POST /anistyle/similar` — `{ source?, frameId | frameIds | image, by?, limit }`(电影只能用 id;广告把 id 转成 shot_ids,图片转给 `/commercials/shots/image`)
108
+ - `GET /anistyle/presets` — `{ boards, checkout }`;`checkout` 表示这份安装能不能把情绪板推回仓库
109
+ - `POST /anistyle/presets` — 把情绪板写入用户数据目录;只有 git 检出才会推送
110
+ - `POST /anistyle/clear-cache` — 清空全部内存缓存(帧 / 网页 / 图片 / 改写 / 画风词表)
111
+ - `GET /anistyle/last` — 最近一次上游响应(诊断)
112
+ - `GET /anistyle/version` — 当前安装的版本号,齿轮菜单底部显示它
113
+
114
+ ## 维护
115
+
116
+ - 两种装法:npm 副本在 `~/.dsh/profiles/<profile>/node_modules/dsh-reference-frames`(用户跑的就是它),开发时用 `link:` 链接检出。
117
+ - 检出里:改 `client.js` 刷新页面;改 `index.js` / `cordis.patch.yml` 重启应用。npm 安装里要先在检出改好再发版,改动经插件页更新下来。
118
+ - 语法自检:`node --check client.js && node --check index.js`。
119
+ - 改名要同步四处:`package.json` 的 `name`、`cordis.patch.yml` 的 `name`、`client.js` 的 `id`,以及 profile 里的登记。
120
+ - 发布:改 `package.json` 版本、写 `CHANGELOG.md`、提交,然后推 `vX.Y.Z` 标签。`.github/workflows/release.yml` 用 trusted publishing 发 npm(不需要 OTP),并以同名标题 `vX.Y.Z` 建 GitHub release。
@@ -0,0 +1,47 @@
1
+ # 参考帧 · DSH 插件
2
+
3
+ [English](../README.md) · [简体中文](README.zh-CN.md)
4
+
5
+ 说一句你想要的感觉,它会找出对味的真实参考帧,供你收进情绪板。
6
+
7
+ ## 安装
8
+
9
+ 前提:DeepSeek Harness。[FrameThrower](https://framethrower.ai) token(`ft_…`,免费注册)用于动画帧源;网页图片源不需要 token,所以没有 token 也能用。
10
+
11
+ `dsh-reference-frames` 已发布到 npm。在 **插件** 页安装,并由该页负责更新。
12
+
13
+ **从 npm 安装。** 插件页 → 添加插件 → `dsh-reference-frames`,或在 `~/.dsh/profiles/<profile>/package.json` 里写:
14
+
15
+ ```json
16
+ {
17
+ "dependencies": { "dsh-reference-frames": "^1.6.0" },
18
+ "dsh": { "profile": { "bundles": ["…", "dsh-reference-frames"] } }
19
+ }
20
+ ```
21
+
22
+ 装好后依赖保存为精确版本,插件详情页的「版本」区块会列出更新的版本,并带 **更新** 按钮。
23
+
24
+ **从源码安装。** 改为链接本机目录:
25
+
26
+ ```json
27
+ {
28
+ "dependencies": { "dsh-reference-frames": "link:/绝对路径/dsh-reference-frames" },
29
+ "dsh": { "profile": { "bundles": ["…", "dsh-reference-frames"] } }
30
+ }
31
+ ```
32
+
33
+ ```bash
34
+ cd ~/.dsh/profiles/<profile> && pnpm install
35
+ ```
36
+
37
+ 链接安装不会在插件页显示版本列表 —— 改完 `git pull` 再重启 Harness 即可。
38
+
39
+ 两种情况都要重启 Harness,侧边栏才会出现 **参考帧**。首次使用在齿轮菜单里填入 token。
40
+
41
+ > `package.json` 的 `name`、`cordis.patch.yml` 的 `name`、`client.js` 顶部的 `id` 必须一致,
42
+ > 漏掉任何一个插件都会静默不加载。
43
+
44
+ ## 文档
45
+
46
+ - [使用与维护](GUIDE.zh-CN.md) — 检索、关键词、情绪板、预设、路由、维护
47
+ - [更新日志](../CHANGELOG.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-reference-frames",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
4
4
  "description": "Reference Frames — search real reference frames (animation, film stills, commercials, web) from a free-form brief (text or image), then collect the ones that land into moodboards.",
5
5
  "license": "MIT",
6
6
  "author": "thu-huangzc (https://github.com/thu-huangzc)",
@@ -33,7 +33,9 @@
33
33
  "cordis.patch.yml",
34
34
  "locale/*.json",
35
35
  "icon.svg",
36
- "presets/moodboards.json"
36
+ "presets/moodboards.json",
37
+ "CHANGELOG.md",
38
+ "docs/*.md"
37
39
  ],
38
40
  "dsh": {
39
41
  "bundle": {