@simula/ads 1.1.0 → 1.3.0

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.
Files changed (87) hide show
  1. package/README.md +51 -356
  2. package/dist/InChatAdSlot.d.ts.map +1 -1
  3. package/dist/components/GameCard.d.ts +11 -0
  4. package/dist/components/GameCard.d.ts.map +1 -0
  5. package/dist/components/GameGrid.d.ts +12 -0
  6. package/dist/components/GameGrid.d.ts.map +1 -0
  7. package/dist/components/GameIframe.d.ts +9 -0
  8. package/dist/components/GameIframe.d.ts.map +1 -0
  9. package/dist/components/MiniGameMenu.d.ts +4 -0
  10. package/dist/components/MiniGameMenu.d.ts.map +1 -0
  11. package/dist/components/inChatAd/InChatAdSlot.d.ts +4 -0
  12. package/dist/components/inChatAd/InChatAdSlot.d.ts.map +1 -0
  13. package/dist/components/miniGame/GameCard.d.ts +11 -0
  14. package/dist/components/miniGame/GameCard.d.ts.map +1 -0
  15. package/dist/components/miniGame/GameGrid.d.ts +12 -0
  16. package/dist/components/miniGame/GameGrid.d.ts.map +1 -0
  17. package/dist/components/miniGame/GameIframe.d.ts +9 -0
  18. package/dist/components/miniGame/GameIframe.d.ts.map +1 -0
  19. package/dist/components/miniGame/MiniGameMenu.d.ts +4 -0
  20. package/dist/components/miniGame/MiniGameMenu.d.ts.map +1 -0
  21. package/dist/components/miniGame/mockGames.d.ts +3 -0
  22. package/dist/components/miniGame/mockGames.d.ts.map +1 -0
  23. package/dist/components/mockGames.d.ts +3 -0
  24. package/dist/components/mockGames.d.ts.map +1 -0
  25. package/dist/components/sponsoredSuggestions/SponsoredSuggestions.d.ts +4 -0
  26. package/dist/components/sponsoredSuggestions/SponsoredSuggestions.d.ts.map +1 -0
  27. package/dist/index.d.ts +121 -4
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +2117 -248
  30. package/dist/index.js.map +1 -1
  31. package/dist/index.mjs +2070 -205
  32. package/dist/index.mjs.map +1 -1
  33. package/dist/types/SimulaProvider.d.ts +5 -0
  34. package/dist/types/SimulaProvider.d.ts.map +1 -0
  35. package/dist/types/components/inChatAd/InChatAdSlot.d.ts +4 -0
  36. package/dist/types/components/inChatAd/InChatAdSlot.d.ts.map +1 -0
  37. package/dist/types/components/miniGame/GameCard.d.ts +12 -0
  38. package/dist/types/components/miniGame/GameCard.d.ts.map +1 -0
  39. package/dist/types/components/miniGame/GameGrid.d.ts +13 -0
  40. package/dist/types/components/miniGame/GameGrid.d.ts.map +1 -0
  41. package/dist/types/components/miniGame/GameIframe.d.ts +21 -0
  42. package/dist/types/components/miniGame/GameIframe.d.ts.map +1 -0
  43. package/dist/types/components/miniGame/MiniGameMenu.d.ts +4 -0
  44. package/dist/types/components/miniGame/MiniGameMenu.d.ts.map +1 -0
  45. package/dist/types/components/miniGame/mockGames.d.ts +3 -0
  46. package/dist/types/components/miniGame/mockGames.d.ts.map +1 -0
  47. package/dist/types/components/nativeBanner/NativeBanner.d.ts +4 -0
  48. package/dist/types/components/nativeBanner/NativeBanner.d.ts.map +1 -0
  49. package/dist/types/components/nativeBanner/NativeBannerTest.d.ts +4 -0
  50. package/dist/types/components/nativeBanner/NativeBannerTest.d.ts.map +1 -0
  51. package/dist/types/components/nativeBanner/RadialLinesSpinner.d.ts +7 -0
  52. package/dist/types/components/nativeBanner/RadialLinesSpinner.d.ts.map +1 -0
  53. package/dist/types/components/nativeBanner/index.d.ts +3 -0
  54. package/dist/types/components/nativeBanner/index.d.ts.map +1 -0
  55. package/dist/types/components/sponsoredSuggestions/SponsoredSuggestions.d.ts +4 -0
  56. package/dist/types/components/sponsoredSuggestions/SponsoredSuggestions.d.ts.map +1 -0
  57. package/dist/types/hooks/useAssetLoadDetection.d.ts +14 -0
  58. package/dist/types/hooks/useAssetLoadDetection.d.ts.map +1 -0
  59. package/dist/types/hooks/useBotDetection.d.ts +3 -0
  60. package/dist/types/hooks/useBotDetection.d.ts.map +1 -0
  61. package/dist/types/hooks/useDebounce.d.ts +2 -0
  62. package/dist/types/hooks/useDebounce.d.ts.map +1 -0
  63. package/dist/types/hooks/useOMIDViewability.d.ts +24 -0
  64. package/dist/types/hooks/useOMIDViewability.d.ts.map +1 -0
  65. package/dist/types/hooks/useViewability.d.ts +6 -0
  66. package/dist/types/hooks/useViewability.d.ts.map +1 -0
  67. package/dist/types/index.d.ts +12 -0
  68. package/dist/types/index.d.ts.map +1 -0
  69. package/dist/types/types.d.ts +189 -0
  70. package/dist/types/types.d.ts.map +1 -0
  71. package/dist/types/utils/api.d.ts +62 -0
  72. package/dist/types/utils/api.d.ts.map +1 -0
  73. package/dist/types/utils/colorThemes.d.ts +21 -0
  74. package/dist/types/utils/colorThemes.d.ts.map +1 -0
  75. package/dist/types/utils/styling.d.ts +4 -0
  76. package/dist/types/utils/styling.d.ts.map +1 -0
  77. package/dist/types/utils/validation.d.ts +27 -0
  78. package/dist/types/utils/validation.d.ts.map +1 -0
  79. package/dist/types.d.ts +51 -2
  80. package/dist/types.d.ts.map +1 -1
  81. package/dist/utils/api.d.ts +2 -3
  82. package/dist/utils/api.d.ts.map +1 -1
  83. package/dist/utils/styling.d.ts +4 -3
  84. package/dist/utils/styling.d.ts.map +1 -1
  85. package/dist/utils/validation.d.ts +2 -7
  86. package/dist/utils/validation.d.ts.map +1 -1
  87. package/package.json +2 -1
package/README.md CHANGED
@@ -1,12 +1,20 @@
1
1
  # Simula Ad SDK
2
2
 
3
- **React SDK for AI-Powered Contextual Ads**
3
+ ## Overview
4
4
 
5
- Simula delivers **contextually relevant ads** for conversational AI apps and LLM-based interfaces. It’s lightweight, easy to integrate, and MRC-compliant out of the box.
5
+ The Simula Ad SDK enables React developers to monetize conversational AI applications with contextually relevant, non-intrusive ads. The SDK provides in-chat ad placements and native banner ads that integrate naturally with chat interfaces.
6
+
7
+ ### Key Features
8
+
9
+ - **Contextual Targeting** - AI-powered ad matching based on conversation content
10
+ - **In-Chat Ad Slots** - Ad placements that blend seamlessly into chat UIs
11
+ - **Native Banner Ads** - Flexible ad placements for feeds and content surfaces
12
+ - **MRC-Compliant Viewability** - Industry-standard impression tracking
13
+ - **Built-in A/B Testing** - Optimize ad performance automatically
6
14
 
7
15
  ---
8
16
 
9
- ## 🚀 Installation
17
+ ## Installation
10
18
 
11
19
  ```bash
12
20
  npm install @simula/ads
@@ -14,393 +22,80 @@ npm install @simula/ads
14
22
 
15
23
  ---
16
24
 
17
- ## Quick Start
25
+ ## Quick Start
18
26
 
19
- Integrate in **two steps**:
27
+ ### 1. Provider Setup
20
28
 
21
- 1. **Wrap your chat/conversation component** with `SimulaProvider`
22
- 2. **Insert** `<InChatAdSlot />` where you want ads
29
+ Wrap your chat/conversation component with `SimulaProvider` to initialize the SDK:
23
30
 
24
31
  ```tsx
25
- import { SimulaProvider, InChatAdSlot } from "@simula/ads";
26
-
27
- function App() {
28
- return (
29
- <div>
30
- <Header />
31
- <ChatInterface /> {/* SimulaProvider wraps individual conversations */}
32
- </div>
33
- );
34
- }
32
+ import { SimulaProvider } from "@simula/ads";
35
33
 
36
34
  function ChatInterface() {
37
- const [messages, setMessages] = useState([]);
38
-
39
35
  return (
40
- <SimulaProvider apiKey="SIMULA_xxx">
41
- <div>
42
- {messages.map((msg, i) => (
43
- <div key={i}>
44
- <p><strong>{msg.role}:</strong> {msg.content}</p>
45
- {msg.role === "assistant" && (
46
- <InChatAdSlot
47
- messages={messages.slice(0, i + 1)}
48
- formats="all"
49
- theme={{ theme: "light", accent: "blue" }}
50
- />
51
- )}
52
- </div>
53
- ))}
54
- </div>
55
- </SimulaProvider>
56
- );
57
- }
58
- ```
59
-
60
- ---
61
-
62
- ## 🧩 Components
63
-
64
- ### `SimulaProvider`
65
-
66
- Initializes the SDK and manages session state.
67
-
68
- | Prop | Type | Required | Default | Description |
69
- | --------------- | ----------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------- |
70
- | `apiKey` | `string` | ✅ | — | Your Simula API key from the [dashboard](https://simula.ad) |
71
- | `children` | `ReactNode` | ✅ | — | Your app components |
72
- | `devMode` | `boolean` | ❌ | `false` | Enables development mode |
73
- | `primaryUserID` | `string` | ❌ | — | Publisher-provided user identifier. **Recommended** for consistent tracking across devices and sessions. |
74
-
75
- ```tsx
76
- // Wrap individual chat/conversation components
77
- function ChatInterface({ conversationId }) {
78
- const [messages, setMessages] = useState([]);
79
-
80
- return (
81
- <SimulaProvider apiKey="SIMULA_xxx">
82
- {/* Your chat UI */}
83
- </SimulaProvider>
84
- );
85
- }
86
-
87
- // For authenticated apps with user tracking (recommended)
88
- function ChatInterface({ conversationId, userId }) {
89
- const [messages, setMessages] = useState([]);
90
-
91
- return (
92
- <SimulaProvider apiKey="SIMULA_xxx" primaryUserID={userId}>
36
+ <SimulaProvider
37
+ apiKey="SIMULA_xxx"
38
+ primaryUserID="user-123" // Optional: User ID for better ad targeting
39
+ hasPrivacyConsent={true} // Optional: Privacy consent flag
40
+ devMode={false} // Optional: Enable dev mode for testing
41
+ >
93
42
  {/* Your chat UI */}
94
43
  </SimulaProvider>
95
44
  );
96
45
  }
97
46
  ```
98
47
 
99
- > **Provider Best Practices**
100
- >
101
- > * **Wrap individual conversations** – Place `SimulaProvider` around each chat or character component so that each conversation is treated as a separate session. This provides better ad targeting based on conversation context.
102
- >
103
- > * **Provide `primaryUserID`** – Use your user's ID to enable cross-device tracking and cookie-independent identification. This approach delivers:
104
- > * **Higher CPMs** – Better user attribution leads to more valuable ad placements
105
- > * **Frequency capping** – Prevents oversending ads to the same user
106
- > * **Better ad experience** – Optimized targeting based on consistent user history
107
- > * **Accurate analytics** – Reliable performance metrics across devices and sessions
108
- >
109
- > * **One provider per conversation** – Don't nest multiple `SimulaProvider` instances. Each conversation/chat component should have its own provider at the top level.
110
- >
111
- > For anonymous users, you can still use `SimulaProvider` without `primaryUserID`, but tracking will rely on cookies.
112
-
113
- ---
114
-
115
- ### `InChatAdSlot`
116
-
117
- Displays an ad based on conversation context.
118
-
119
- | Prop | Type | Required | Default | Description |
120
- | -------------- | ---------------------- | -------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
121
- | `messages` | `Message[]` | ✅ | — | Array of `{ role, content }`; pass recent conversation (e.g. last 6 turns). |
122
- | `trigger` | `Promise<any>` | ❌ | Fires immediately on viewability | Promise to await before fetching the ad (e.g. LLM call). |
123
- | `formats` | `string \| string[]` | ❌ | `['all']` | Preferred ad formats: `'all'`, `'tips'`, `'interactive'`, `'suggestions'`, `'text'`, `'highlight'`, `'visual_banner'`, `'image_feature'`, or an array like `['text', 'highlight']`. See [Appendix: Ad Formats](#appendix-ad-formats) for visual examples.<br>**A/B Testing:** Pass an array to automatically A/B test different formats and let Simula pick the best over time. |
124
- | `theme` | `SimulaTheme` | ❌ | `{ theme: 'auto', width: 'auto', accent: ['neutral','image'], font: 'sans-serif', cornerRadius: 8 }` | Customize ad appearance (see Theme Options). Arrays trigger A/B testing. |
125
- | `charDesc` | `string` | ❌ | `undefined` | Character description for additional context to improve ad targeting. |
126
- | `debounceMs` | `number` | ❌ | `0` | Delay in milliseconds before fetching. |
127
- | `onImpression` | `(ad: AdData) => void` | ❌ | `undefined` | Callback when ad is viewable (50% visible for ≥1s). |
128
- | `onClick` | `(ad: AdData) => void` | ❌ | `undefined` | Callback when ad is clicked. |
129
- | `onError` | `(err: Error) => void` | ❌ | `undefined` | Callback when ad fails or no-fill occurs. |
130
-
131
- **Behavior:**
132
-
133
- * Fetches **once** per slot (static)
134
- * Triggers on **viewport visibility** (50% visible)
135
- * Includes built-in **bot protection**
136
- * Tracks impressions **MRC-compliantly**
137
-
138
- ---
139
-
140
- ## 🎨 Theme Options
141
-
142
- ```ts
143
- interface SimulaTheme {
144
- theme?: "light" | "dark" | "auto"; // default: "auto"
145
- accent?: AccentOption | AccentOption[]; // default: ["neutral", "image"] (A/B tested)
146
- font?: FontOption | FontOption[]; // default: "sans-serif"
147
- width?: number | string; // default: "auto" (min 320px)
148
- cornerRadius?: number; // default: 8
149
- }
150
- ```
151
-
152
- **Modes:** `light` | `dark` | `auto`
153
- **Accents:**
154
- `blue`, `red`, `green`, `yellow`, `purple`, `pink`, `orange`, `neutral`, `gray`, `tan`, `transparent`, `image`
155
- **Fonts:** `sans-serif`, `serif`, `monospace`
156
-
157
- > **Height:** fixed at **265px**
158
- > **Width:** min **320px**, accepts px/%, or `auto`
159
-
160
- > **A/B Testing:**
161
- > When you pass an **array** (e.g., `accent: ['blue', 'green', 'purple']`), Simula will **automatically A/B test** across the provided options—colors, fonts, or formats—and **optimize over time for the best-performing variant**.
162
-
163
- ```tsx
164
- // Default theme (auto)
165
- <InChatAdSlot messages={messages} />
166
-
167
- // Light theme
168
- <InChatAdSlot messages={messages} theme={{ theme: "light", accent: "blue" }} />
169
-
170
- // Dark theme with custom width
171
- <InChatAdSlot
172
- messages={messages}
173
- theme={{ theme: "dark", accent: "purple", width: 600, cornerRadius: 12 }}
174
- />
175
-
176
- // A/B testing
177
- <InChatAdSlot
178
- messages={messages}
179
- theme={{
180
- accent: ["blue", "green", "purple"], // A/B test colors
181
- font: ["sans-serif", "serif"], // A/B test fonts
182
- width: "100%"
183
- }}
184
- />
185
- ```
186
-
187
- ---
188
-
189
- ## 💬 Integration Example
48
+ ### 2. Component Integration
190
49
 
191
- ### Chat App with OpenAI
50
+ Add components where you want ads to appear:
192
51
 
52
+ **In-Chat Ads:**
193
53
  ```tsx
194
- import { useState } from "react";
195
- import { SimulaProvider, InChatAdSlot } from "@simula/ads";
196
- import OpenAI from "openai";
54
+ import { InChatAdSlot } from "@simula/ads";
197
55
 
198
- const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
199
-
200
- export default function App() {
201
- return (
202
- <div>
203
- <Header />
204
- <ChatApp /> {/* Each conversation has its own SimulaProvider */}
205
- </div>
206
- );
207
- }
208
-
209
- function ChatApp() {
210
- const [messages, setMessages] = useState([]);
211
- const [input, setInput] = useState("");
212
- const [loading, setLoading] = useState(false);
213
-
214
- async function sendMessage() {
215
- if (!input.trim()) return;
216
-
217
- const userMessage = { role: "user", content: input.trim() };
218
- const newMessages = [...messages, userMessage];
219
- setMessages(newMessages);
220
- setInput("");
221
- setLoading(true);
222
-
223
- try {
224
- const llmPromise = client.chat.completions.create({
225
- model: "gpt-4o-mini",
226
- messages: newMessages,
227
- });
228
-
229
- const res = await llmPromise;
230
- const reply = res.choices[0].message;
231
-
232
- setMessages((prev) => [...prev, { ...reply, llmPromise }]);
233
- } finally {
234
- setLoading(false);
235
- }
236
- }
237
-
238
- return (
239
- <SimulaProvider apiKey="SIMULA_xxx">
240
- <div className="chat">
241
- {messages.map((msg, i) => (
242
- <div key={i}>
243
- <p><strong>{msg.role}:</strong> {msg.content}</p>
244
-
245
- {msg.role === "assistant" && (
246
- <InChatAdSlot
247
- key={`adslot-${i}`} // ✅ Required if rendering in a list
248
- trigger={msg.llmPromise} // default: fires immediately if not provided
249
- messages={messages.slice(0, i + 1)}
250
- formats="all"
251
- theme={{ theme: "light", accent: "blue", width: "auto" }}
252
- />
253
- )}
254
- </div>
255
- ))}
256
-
257
- <input
258
- value={input}
259
- onChange={(e) => setInput(e.target.value)}
260
- onKeyDown={(e) => e.key === "Enter" && sendMessage()}
261
- />
262
- <button onClick={sendMessage} disabled={loading}>Send</button>
263
- </div>
264
- </SimulaProvider>
265
- );
266
- }
267
- ```
268
-
269
- > **Tips:**
270
- >
271
- > * **Wrap `SimulaProvider` around the chat component** – This treats each conversation as a separate session for better ad targeting.
272
- > * Use `key` prop when `<InChatAdSlot />` is rendered inside a list or dynamic loop.
273
- > * The `trigger` prop waits for the LLM response before fetching ads. If omitted, the ad fetches immediately when viewable.
274
-
275
- ---
276
-
277
- ## 🔑 Features
278
-
279
- * **Contextual Targeting** – AI-powered ad matching to conversation content
280
- * **Bot Protection** – via [@fingerprintjs/botd](https://github.com/fingerprintjs/botd)
281
- * **MRC-Compliant Viewability** – 50% visible for ≥1s
282
- * **Responsive** – Flexible widths with enforced minimums
283
- * **Static Fetch** – Each slot fetches once and stays fixed
284
- * **Session Management** – Automatic
285
- * **Robust Error Handling** – Graceful degradation & callbacks
286
- * **TypeScript Support** – Built-in type definitions
287
- * **Built-in A/B Testing** – Test multiple colors, formats, or fonts by passing arrays and let Simula optimize performance over time
288
-
289
- ---
290
-
291
- ## ⚙️ Advanced Usage
292
-
293
- ### Event Handlers
294
-
295
- ```tsx
296
56
  <InChatAdSlot
297
- messages={messages}
298
- onImpression={(ad) => console.log("Impression:", ad.id)} // default: none
299
- onClick={(ad) => console.log("Clicked:", ad.id)} // default: none
300
- onError={(err) => console.error("Ad error:", err)} // default: none
57
+ messages={messages.slice(0, i + 1)}
58
+ theme={{ mode: "light", accent: "blue" }}
59
+ onImpression={(ad) => console.log("Impression:", ad.id)}
60
+ onError={(err) => console.error("Ad error:", err)}
301
61
  />
302
62
  ```
303
63
 
304
- ### Debounce Fetching
305
-
64
+ **Native Banner Ads:**
306
65
  ```tsx
307
- <InChatAdSlot
308
- messages={messages}
309
- debounceMs={500} // default: 0
66
+ import { NativeBanner } from "@simula/ads";
67
+
68
+ <NativeBanner
69
+ slot="feed"
70
+ position={index}
71
+ context={{
72
+ searchTerm: "cooking recipes",
73
+ tags: ["food", "cooking"],
74
+ }}
75
+ width="100%"
76
+ onImpression={(ad) => console.log("Impression:", ad.id)}
77
+ onError={(err) => console.error("Error:", err)}
310
78
  />
311
79
  ```
312
80
 
313
81
  ---
314
82
 
315
- ## 📦 TypeScript Types
316
-
317
- ```ts
318
- import type {
319
- SimulaTheme,
320
- Message,
321
- AdData,
322
- InChatAdSlotProps,
323
- SimulaProviderProps
324
- } from "@simula/ads";
325
- ```
326
-
327
- ---
83
+ ## Documentation
328
84
 
329
- ## 📚 Resources
85
+ For complete API reference, integration guides, and examples:
330
86
 
331
- * [Website](https://simula.ad)
332
- * [GitHub Issues](https://github.com/Simula-AI-SDK/simula-ad-sdk/issues)
333
- * Support: **[admin@simula.ad](mailto:admin@simula.ad)**
87
+ - **[InChatAdSlot Documentation](https://simula-ad.notion.site/?pvs=73)**
88
+ - **[NativeBanner Documentation](https://simula-ad.notion.site/Komiko-Simula-Integration-2cbaf70f6f0d80338ddcd2efbbe5d3d7?source=copy_link)**
334
89
 
335
90
  ---
336
91
 
337
- ## 📄 License
92
+ ## Support
338
93
 
339
- MIT
94
+ - **Website:** [simula.ad](https://simula.ad)
95
+ - **Email:** [admin@simula.ad](mailto:admin@simula.ad)
340
96
 
341
97
  ---
342
98
 
343
- ## 📑 Appendix: Ad Formats
344
-
345
- Visual examples of all available ad formats across mobile and desktop:
346
-
347
- | Format | Mobile | Desktop |
348
- |--------|--------|---------|
349
- | **tips** | <img src="./assets/tips_mobile.png" width="200" alt="Tips format on mobile" /> | <img src="./assets/tips_desktop.png" width="400" alt="Tips format on desktop" /> |
350
- | **interactive** | <img src="./assets/interactive_mobile.png" width="200" alt="Interactive format on mobile" /> | <img src="./assets/interactive_desktop.png" width="400" alt="Interactive format on desktop" /> |
351
- | **suggestions** | <img src="./assets/suggestions_mobile.png" width="200" alt="Suggestions format on mobile" /> | <img src="./assets/suggestions_desktop.png" width="400" alt="Suggestions format on desktop" /> |
352
- | **text** | <img src="./assets/text_mobile.png" width="200" alt="Text format on mobile" /> | <img src="./assets/text_desktop.png" width="400" alt="Text format on desktop" /> |
353
- | **highlight** | <img src="./assets/highlight_mobile.png" width="200" alt="Highlight format on mobile" /> | <img src="./assets/highlight_desktop.png" width="400" alt="Highlight format on desktop" /> |
354
- | **visual_banner** | <img src="./assets/visual_banner_mobile.png" width="200" alt="Visual banner format on mobile" /> | <img src="./assets/visual_banner_desktop.png" width="400" alt="Visual banner format on desktop" /> |
355
- | **image_feature** | <img src="./assets/image_feature_mobile.png" width="200" alt="Image feature format on mobile" /> | <img src="./assets/image_feature_desktop.png" width="400" alt="Image feature format on desktop" /> |
356
-
357
- > **Note:** The `'all'` format allows Simula to automatically select the best format based on context and performance.
358
-
359
- ---
360
-
361
- ## 📑 Appendix: Invalid Format & Accent Combinations
362
-
363
- Certain ad formats have restrictions on which accent colors can be used. **These restrictions only apply when you specify an invalid combination with no other valid options.** When A/B testing with arrays, Simula automatically selects valid combinations from the available options.
99
+ ## License
364
100
 
365
- | Format | Allowed Accents | Restrictions |
366
- |--------|----------------|--------------|
367
- | **interactive** | All colors, `'image'`, `'neutral'`, `'gray'`, `'tan'` | ❌ Cannot use `'transparent'` |
368
- | **tips** | All colors, `'image'`, `'neutral'`, `'gray'`, `'tan'` | ❌ Cannot use `'transparent'` |
369
- | **text** | **Only** `'transparent'` | ❌ Cannot use colors or `'image'` |
370
- | **highlight** | All colors, `'image'`, `'neutral'`, `'gray'`, `'tan'` | ❌ Cannot use `'transparent'` |
371
- | **visual_banner** | All colors, `'neutral'`, `'gray'`, `'tan'` | ❌ Cannot use `'image'` or `'transparent'` |
372
- | **image_feature** | All colors, `'neutral'`, `'gray'`, `'tan'` | ❌ Cannot use `'image'` or `'transparent'` |
373
- | **suggestions** | All accents allowed | ✅ No restrictions |
374
-
375
- **Color accents:** `'blue'`, `'red'`, `'green'`, `'yellow'`, `'purple'`, `'pink'`, `'orange'`, `'neutral'`, `'gray'`, `'tan'`
376
-
377
- ### Examples
378
-
379
- ```tsx
380
- // ✅ Valid - single format, single accent
381
- <InChatAdSlot formats="interactive" theme={{ accent: "blue" }} />
382
- <InChatAdSlot formats="text" theme={{ accent: "transparent" }} />
383
- <InChatAdSlot formats="visual_banner" theme={{ accent: "purple" }} />
384
-
385
- // ✅ Valid - A/B testing with arrays (Simula auto-selects valid combinations)
386
- <InChatAdSlot
387
- formats={['text', 'highlight']}
388
- theme={{ accent: ['image', 'transparent'] }}
389
- />
390
- // If 'text' is selected → uses 'transparent' (skips 'image')
391
- // If 'highlight' is selected → uses 'image' (skips 'transparent')
392
-
393
- <InChatAdSlot
394
- formats={['interactive', 'visual_banner']}
395
- theme={{ accent: ['blue', 'transparent'] }}
396
- />
397
- // If 'interactive' is selected → uses 'blue' (skips 'transparent')
398
- // If 'visual_banner' is selected → uses 'blue' (skips 'transparent')
399
-
400
- // ❌ Invalid - no valid options available
401
- <InChatAdSlot formats="interactive" theme={{ accent: "transparent" }} /> // interactive cannot use transparent (no fallback)
402
- <InChatAdSlot formats="text" theme={{ accent: "blue" }} /> // text can ONLY use transparent (no fallback)
403
- <InChatAdSlot formats="text" theme={{ accent: ['blue', 'red', 'image'] }} /> // text needs transparent but none provided
404
- ```
405
-
406
- > **Key Point:** Restrictions only matter when there are **no valid alternatives**. When A/B testing with multiple formats or accents, Simula intelligently matches compatible combinations.
101
+ MIT
@@ -1 +1 @@
1
- {"version":3,"file":"InChatAdSlot.d.ts","sourceRoot":"","sources":["../src/InChatAdSlot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AASjF,OAAO,EAAE,iBAAiB,EAAU,MAAM,SAAS,CAAC;AAepD,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAyXpD,CAAC"}
1
+ {"version":3,"file":"InChatAdSlot.d.ts","sourceRoot":"","sources":["../src/InChatAdSlot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AASjF,OAAO,EAAE,iBAAiB,EAAU,MAAM,SAAS,CAAC;AAepD,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAqXpD,CAAC"}
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import { GameData, MiniGameTheme } from '../types';
3
+ interface GameCardProps {
4
+ game: GameData;
5
+ charID: string;
6
+ theme: MiniGameTheme;
7
+ onGameSelect: (gameId: string) => void;
8
+ }
9
+ export declare const GameCard: React.FC<GameCardProps>;
10
+ export {};
11
+ //# sourceMappingURL=GameCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GameCard.d.ts","sourceRoot":"","sources":["../../src/components/GameCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEnD,UAAU,aAAa;IACrB,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,aAAa,CAAC;IACrB,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA+N5C,CAAC"}
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { GameData, MiniGameTheme } from '../types';
3
+ interface GameGridProps {
4
+ games: GameData[];
5
+ maxGamesToShow: 3 | 6 | 9;
6
+ charID: string;
7
+ theme: MiniGameTheme;
8
+ onGameSelect: (gameId: string) => void;
9
+ }
10
+ export declare const GameGrid: React.FC<GameGridProps>;
11
+ export {};
12
+ //# sourceMappingURL=GameGrid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GameGrid.d.ts","sourceRoot":"","sources":["../../src/components/GameGrid.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGnD,UAAU,aAAa;IACrB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,cAAc,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,aAAa,CAAC;IACrB,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA0K5C,CAAC"}
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ interface GameIframeProps {
3
+ gameId: string;
4
+ charID: string;
5
+ onClose: () => void;
6
+ }
7
+ export declare const GameIframe: React.FC<GameIframeProps>;
8
+ export {};
9
+ //# sourceMappingURL=GameIframe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GameIframe.d.ts","sourceRoot":"","sources":["../../src/components/GameIframe.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAGjD,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAsHhD,CAAC"}
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import { MiniGameMenuProps } from '../types';
3
+ export declare const MiniGameMenu: React.FC<MiniGameMenuProps>;
4
+ //# sourceMappingURL=MiniGameMenu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MiniGameMenu.d.ts","sourceRoot":"","sources":["../../src/components/MiniGameMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAiB,MAAM,UAAU,CAAC;AAc5D,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAqVpD,CAAC"}
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import { InChatAdSlotProps } from '../../types';
3
+ export declare const InChatAdSlot: React.FC<InChatAdSlotProps>;
4
+ //# sourceMappingURL=InChatAdSlot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InChatAdSlot.d.ts","sourceRoot":"","sources":["../../../src/components/inChatAd/InChatAdSlot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AASjF,OAAO,EAAE,iBAAiB,EAAU,MAAM,aAAa,CAAC;AAexD,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAqXpD,CAAC"}
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import { GameData, MiniGameTheme } from '../../types';
3
+ interface GameCardProps {
4
+ game: GameData;
5
+ charID: string;
6
+ theme: MiniGameTheme;
7
+ onGameSelect: (gameId: string) => void;
8
+ }
9
+ export declare const GameCard: React.FC<GameCardProps>;
10
+ export {};
11
+ //# sourceMappingURL=GameCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GameCard.d.ts","sourceRoot":"","sources":["../../../src/components/miniGame/GameCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEtD,UAAU,aAAa;IACrB,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,aAAa,CAAC;IACrB,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA+N5C,CAAC"}
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { GameData, MiniGameTheme } from '../../types';
3
+ interface GameGridProps {
4
+ games: GameData[];
5
+ maxGamesToShow: 3 | 6 | 9;
6
+ charID: string;
7
+ theme: MiniGameTheme;
8
+ onGameSelect: (gameId: string) => void;
9
+ }
10
+ export declare const GameGrid: React.FC<GameGridProps>;
11
+ export {};
12
+ //# sourceMappingURL=GameGrid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GameGrid.d.ts","sourceRoot":"","sources":["../../../src/components/miniGame/GameGrid.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGtD,UAAU,aAAa;IACrB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,cAAc,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,aAAa,CAAC;IACrB,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA0K5C,CAAC"}
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ interface GameIframeProps {
3
+ gameId: string;
4
+ charID: string;
5
+ onClose: () => void;
6
+ }
7
+ export declare const GameIframe: React.FC<GameIframeProps>;
8
+ export {};
9
+ //# sourceMappingURL=GameIframe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GameIframe.d.ts","sourceRoot":"","sources":["../../../src/components/miniGame/GameIframe.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAGjD,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAsHhD,CAAC"}
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import { MiniGameMenuProps } from '../../types';
3
+ export declare const MiniGameMenu: React.FC<MiniGameMenuProps>;
4
+ //# sourceMappingURL=MiniGameMenu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MiniGameMenu.d.ts","sourceRoot":"","sources":["../../../src/components/miniGame/MiniGameMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAiB,MAAM,aAAa,CAAC;AAc/D,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAqVpD,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { GameData } from '../../types';
2
+ export declare const mockGames: GameData[];
3
+ //# sourceMappingURL=mockGames.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mockGames.d.ts","sourceRoot":"","sources":["../../../src/components/miniGame/mockGames.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,eAAO,MAAM,SAAS,EAAE,QAAQ,EAuD/B,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { GameData } from '../types';
2
+ export declare const mockGames: GameData[];
3
+ //# sourceMappingURL=mockGames.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mockGames.d.ts","sourceRoot":"","sources":["../../src/components/mockGames.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,eAAO,MAAM,SAAS,EAAE,QAAQ,EAuD/B,CAAC"}
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import { SponsoredSuggestionsProps } from '../../types';
3
+ export declare const SponsoredSuggestions: React.FC<SponsoredSuggestionsProps>;
4
+ //# sourceMappingURL=SponsoredSuggestions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SponsoredSuggestions.d.ts","sourceRoot":"","sources":["../../../src/components/sponsoredSuggestions/SponsoredSuggestions.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,yBAAyB,EAA2B,MAAM,aAAa,CAAC;AAYjF,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CAkJpE,CAAC"}