@melite/models-anima 0.1.4-alpha → 0.1.5-pre-alpha

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/README.md ADDED
@@ -0,0 +1,36 @@
1
+ ---
2
+ description: Anima text-to-image family, a Cosmos-Predict2 anime and illustration diffusion lane with Danbooru-style prompting.
3
+ kind: package-library
4
+ ---
5
+
6
+ # @melite/models-anima
7
+
8
+ The Anima family — anime and illustration text-to-image on the comfyui engine, built on the Cosmos-Predict2 base with Danbooru-style prompting. The package owns the declaration, the lane's weight facts, and the t2i action; the image-gen card binds the action and owns the compose surface around it.
9
+
10
+ The lane pins its weights in lane_inputs: unet `anima-base-v1.0.safetensors`, text encoder `qwen_3_06b_base.safetensors`, VAE `qwen_image_vae.safetensors`, clip type `stable_diffusion`, stock `EmptyLatentImage` latent. Three provisions rows download them (circlestone-labs/Anima, Qwen/Qwen3-0.6B-Base, Comfy-Org/Qwen-Image_ComfyUI). Defaults are 1024×1024, 30 steps, er_sde over simple, cfg 4; the recipes are draft (8 steps) and detailed (30 steps); the single F32 cell peaks at 20 GB. The prompt field is required — a draft without one refuses, because every image lane states what the picture is.
11
+
12
+ The family's action is t2i: the stock diffuse topology — CLIPTextEncode pair, EmptyLatentImage at card resolution, KSampler, decode and save under `<run>/gen`. The facts door reads the resolved lane_inputs into the closed T2IFacts shape; a drifted latent class refuses rather than silently rerouting. Anima boards no mods: loras, controlnets, and ip-adapter bags refuse loud, never silently drop.
13
+
14
+ ## Declaration
15
+
16
+ `src/index.ts` declares the DECL and the `family-anima` plugin; `src/actions.ts` owns the t2i segment and its typed facts and params.
17
+
18
+ ## Model Experience
19
+
20
+ #### What the model sees
21
+
22
+ None — the package contributes no model-visible input. The DECL serves the estate's model catalog (label, description, variants, defaults) and the image-gen card that boards the family; it registers no session events and writes no prompt segments.
23
+
24
+ #### Token effect
25
+
26
+ Zero-direct token effect — the package registers a model family and composes engine graphs; it writes no prompt text into any model request.
27
+
28
+ #### KV Cache effect
29
+
30
+ Independent — the package contributes no persistent prompt prefix, so registering or removing the family invalidates nothing cached.
31
+
32
+ ## Known Limitations and Deferred Work
33
+
34
+ - **Required prompt** — the relations row makes prompt mandatory; a textless draft refuses at the family door instead of composing an undefined image.
35
+ - **F32 only** — one cell, 20 GB peak; no quantized variants ride the DECL.
36
+ - **No adapter flavor** — no loras or controlnets packs board the family; a stated adapter bag refuses loud, so adapter-driven styling is out of scope here.
package/lib/actions.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { loadTextPair, decodeSave, stackLoras, stackControlNets } from "@melite/comfyui-card-kit";
2
2
  import { fireLoras, fireControlNets, refuseIPAdapterFiring } from "@melite/comfyui-card-kit/guard";
3
- import { requireText } from "@melite/comfyui-card-kit/facts";
3
+ import { parseDiffusionLaneFacts } from "@melite/comfyui-card-kit/facts";
4
4
  import { diffusionParamRows } from "@melite/comfyui-card-kit/paramRows";
5
+ import { checkAnimaPromptTags } from "./promptTags.js";
5
6
  /** The t2i facts door: the resolved lane_inputs parsed into the
6
7
  * closed shape. A drifted latent class refuses here, never
7
8
  * silently routes to another topology. `sampling_shift: 0` is
@@ -10,23 +11,11 @@ import { diffusionParamRows } from "@melite/comfyui-card-kit/paramRows";
10
11
  * @param raw the resolved lane_inputs (family ⊕ variant)
11
12
  * @returns the typed facts the segment factory reads */
12
13
  export function parseT2IFacts(raw) {
13
- const text = (key) => requireText(raw, key, "anima t2i");
14
- const node = raw.latent_node;
15
- if (node !== "EmptyLatentImage") {
16
- throw new Error(`anima t2i: lane_inputs.latent_node = ${JSON.stringify(node)} — the t2i action builds on EmptyLatentImage`);
17
- }
18
- const shift = raw.sampling_shift;
19
- if (shift !== undefined && typeof shift !== "number") {
20
- throw new Error(`anima t2i: lane_inputs.sampling_shift = ${JSON.stringify(shift)} — a number is required`);
21
- }
22
- return {
23
- unet: text("unet"),
24
- text_encoder: text("text_encoder"),
25
- vae: text("vae"),
26
- clip_type: text("clip_type"),
27
- latent_node: node,
28
- sampling_shift: shift,
29
- };
14
+ // The checks + refusal prose live in the kit (J2 consolidation,
15
+
16
+ // family's own typed shape (the self-containment contract, B4).
17
+ const f = parseDiffusionLaneFacts(raw, "anima t2i", { key: "latent_node", node: "EmptyLatentImage" });
18
+ return { unet: f.unet, text_encoder: f.text_encoder, vae: f.vae, clip_type: f.clip_type, latent_node: f.node, sampling_shift: f.sampling_shift };
30
19
  }
31
20
  /** The text-to-image action: the stock diffuse topology — CLIP
32
21
  * encoder pair (positive + negative), EmptyLatentImage at card
@@ -57,6 +46,13 @@ export const t2i = {
57
46
  // vocabulary, mod-level owned; anima boards no pack, the picks
58
47
  // are always empty — the call stays so a stated bag refuses).
59
48
  unet = stackControlNets(g, unet, vae, fireControlNets(model, p));
49
+ // THE TAG-GRAMMAR DOOR (features/001 A4): the Danbooru grammar
50
+ // is mechanical — a malformed prompt refuses here with the
51
+ // fragment named, never reaches the encoder silently rewritten.
52
+ checkAnimaPromptTags("prompt", p.prompt);
53
+ if (p.negative_prompt !== undefined) {
54
+ checkAnimaPromptTags("negative_prompt", p.negative_prompt);
55
+ }
60
56
  const pos = g.node("CLIPTextEncode", { clip, text: p.prompt });
61
57
  const neg = g.node("CLIPTextEncode", { clip, text: p.negative_prompt ?? "" });
62
58
  const latent = g.node(facts.latent_node, { batch_size: 1, width: p.width, height: p.height });
package/lib/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { Plugin } from "@deepseek-ai/cordis";
2
- import type { ModelDecl } from "@melite/comfyui-cordis/model-contract";
2
+ import type { ModelDecl } from '@melite/comfyui-card-kit/model-contract';
3
3
  export declare const DECL: ModelDecl;
4
4
  export declare const family: Plugin;
5
5
  export { t2i, parseT2IFacts, type T2IFacts, type T2IParams } from "./actions.js";
6
+ export { family as default };
6
7
  //# sourceMappingURL=index.d.ts.map
package/lib/index.js CHANGED
@@ -14,6 +14,11 @@ export const DECL = {
14
14
  "cfg": 4
15
15
  },
16
16
  "genre": "image",
17
+ // MASK-C (the image-gen region gap — deliberate no-board): no
18
+ // mods key (absent ≡ boards nothing) — the anime T2I lane takes no
19
+ // region input upstream and no edit lane shares these weights.
20
+ // Serving the surface would promise what no lane builds; a stated
21
+ // mask refuses LOUD at admission like every undeclared key.
17
22
  "variants": [
18
23
  {
19
24
  "id": "standard",
@@ -45,6 +50,14 @@ export const DECL = {
45
50
  "wire_defaults": { "steps": 30 },
46
51
  "cells": [],
47
52
  },
53
+ {
54
+ "id": "settled-negative",
55
+ "label": "Settled negative",
56
+ "hint": "Stamps the guide's settled negative set. TRIM RULE: the negative stays short — broadening a negative concept degrades quality, so this row is the whole set, never a base to widen.",
57
+ "group": "Recipe",
58
+ "wire_defaults": { "negative_prompt": "worst quality, low quality, score_1, score_2, score_3, artist name" },
59
+ "cells": [],
60
+ },
48
61
  {
49
62
  "id": "default",
50
63
  "label": "Default",
@@ -69,6 +82,20 @@ export const DECL = {
69
82
  "default": "default"
70
83
  }
71
84
  ],
85
+ // THE LANE SURFACE (the edit-2511 precedent): exactly the knobs the
86
+ // create card serves — no reference seat (operator ruling,
87
+
88
+ "params": [
89
+ "prompt",
90
+ "negative_prompt",
91
+ "width",
92
+ "height",
93
+ "seed",
94
+ "steps",
95
+ "cfg",
96
+ "sampler",
97
+ "scheduler",
98
+ ],
72
99
  "lane_inputs": {
73
100
  "clip_type": "stable_diffusion",
74
101
  "latent_node": "EmptyLatentImage",
@@ -138,4 +165,9 @@ export const family = {
138
165
  // segment the image-gen card binds. The card imports this beside
139
166
  // the DECL — the family's whole offer, one face.
140
167
  export { t2i, parseT2IFacts } from "./actions.js";
168
+ // The Loader-row face: DSH loads plugin rows by bare specifier and
169
+ // unwraps `exports.default ?? exports` (vendor/cordis_plugins/loader
170
+ // unwrapExports) — the default export IS the row-loadable plugin. The
171
+ // named `family` stays the library face (engine loadFamilies).
172
+ export { family as default };
141
173
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,9 @@
1
+ /** Refuse a prompt or negative that breaks the Danbooru tag
2
+ * grammar. Called from the t2i build before any node renders —
3
+ * a malformed grammar dies at compose time with the offending
4
+ * fragment named, never at the encoder.
5
+ * @param field the param seat being judged ("prompt" or "negative_prompt")
6
+ * @param text the raw param value
7
+ * @throws Error naming the refusal class and the offending fragment */
8
+ export declare function checkAnimaPromptTags(field: "prompt" | "negative_prompt", text: string): void;
9
+ //# sourceMappingURL=promptTags.d.ts.map
@@ -0,0 +1,49 @@
1
+ // @melite/models-anima/src/promptTags — the Danbooru tag-grammar
2
+
3
+ // is mechanical, so the family REFUSES a prompt that breaks it —
4
+ // never silently rewrites (a rewritten prompt is a different
5
+ // picture, and the author never learns their tags are malformed).
6
+ // Three refusal classes, one door: missing space after a comma,
7
+ // doubled comma, underscore in a tag. The score-tag exception is
8
+ // the recipe's own rule (score_1..score_9 are the one legal
9
+ // underscore form — "spaces instead of underscores, except score
10
+ // tags").
11
+ /** An underscore-bearing token that is NOT a score tag
12
+ * (score_[0-9] with optional decimals) — the recipe's one legal
13
+ * underscore form. */
14
+ function isScoreTag(token) {
15
+ return /^score_[0-9](\.[0-9]+)?$/.test(token);
16
+ }
17
+ /** Refuse a prompt or negative that breaks the Danbooru tag
18
+ * grammar. Called from the t2i build before any node renders —
19
+ * a malformed grammar dies at compose time with the offending
20
+ * fragment named, never at the encoder.
21
+ * @param field the param seat being judged ("prompt" or "negative_prompt")
22
+ * @param text the raw param value
23
+ * @throws Error naming the refusal class and the offending fragment */
24
+ export function checkAnimaPromptTags(field, text) {
25
+ const segments = text.split(",");
26
+ for (let i = 0; i < segments.length; i += 1) {
27
+ const seg = segments[i];
28
+ // class 2 — doubled comma: an empty segment anywhere except a
29
+ // trailing one (a prompt ending in a single comma is the
30
+ // prefix convention, not a doubled separator).
31
+ if (seg.trim() === "" && i < segments.length - 1) {
32
+ throw new Error(`anima ${field}: doubled comma at segment ${i + 1} — one comma, one space, then the next tag (${JSON.stringify(text)})`);
33
+ }
34
+ // class 1 — missing space after a comma: the separator grammar
35
+ // is ", " (comma + space); a comma glued to the next tag
36
+ // refuses (the first segment has no comma in front of it).
37
+ if (i > 0 && seg !== "" && !seg.startsWith(" ")) {
38
+ throw new Error(`anima ${field}: missing space after comma before ${JSON.stringify(seg)} — the separator is comma + space (${JSON.stringify(text)})`);
39
+ }
40
+ // class 3 — underscore in a tag: Danbooru tags use spaces;
41
+ // the score tags are the exception, per the recipe.
42
+ for (const token of seg.trim().split(/\s+/)) {
43
+ if (token.includes("_") && !isScoreTag(token)) {
44
+ throw new Error(`anima ${field}: underscore in tag ${JSON.stringify(token)} — tags use spaces; only score tags (score_1..score_9) keep the underscore (${JSON.stringify(text)})`);
45
+ }
46
+ }
47
+ }
48
+ }
49
+ //# sourceMappingURL=promptTags.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@melite/models-anima",
3
- "version": "0.1.4-alpha",
3
+ "version": "0.1.5-pre-alpha",
4
4
  "license": "SSPL-1.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -11,8 +11,7 @@
11
11
  "./package.json": "./package.json"
12
12
  },
13
13
  "dependencies": {
14
- "@melite/comfyui-cordis": "0.1.4-alpha",
15
- "@melite/comfyui-card-kit": "0.1.4-alpha"
14
+ "@melite/comfyui-card-kit": "0.1.5-pre-alpha"
16
15
  },
17
16
  "devDependencies": {
18
17
  "@types/node": "^22.20.0",