This page serves as a live documentation and testing environment for the DFC Game Widget.
Current API URL: Loading...
Дата: 04.08.2026 | Тип: patch
Миграция не требуется.
Отсутствуют.
Полная история изменений доступна в versions.md
To embed the widget on your site, include resource hints in your HTML <head> and scripts at the end of the <body> tag. These URLs point to the staging environment.
<!-- DFC Widget Scripts -->
<link rel="preconnect" href="https://staging.widget.game.dapp.expert" crossorigin>
<link rel="preconnect" href="https://staging.api.game.dapp.expert" crossorigin>
<link rel="dns-prefetch" href="//staging.widget.game.dapp.expert">
<link rel="dns-prefetch" href="//staging.api.game.dapp.expert">
<script src="https://staging.widget.game.dapp.expert/runtime.js?v=BUILD_VERSION"></script>
<script src="https://staging.widget.game.dapp.expert/polyfills.js?v=BUILD_VERSION"></script>
<script src="https://staging.widget.game.dapp.expert/main.js?v=BUILD_VERSION"></script>
The scripts expose a global window.dfcGame object with the following API:
window.dfcGame.init(config): Promise<HTMLElement | void>: Initializes and renders the widget on the page. It takes an optional configuration object and resolves with the dfc-game element once the Angular application exists and the element is attached to the host. It does not mean that auth, the toolbar or data are ready; see Readiness Events and Timestamps below.window.dfcGame.destroy(): void: Destroys the widget instance and removes it from the DOM.window.dfcGame.restart(config): Promise<void>: Restarts the widget with the same or updated configuration.window.dfcGame.waitForReady(timeout): Promise<void>: Waits until window.dfcGame.isReady becomes true, meaning the API object exists and init() may be called. It does not wait for auth, the toolbar or data. Polls every 50 ms; rejects with an Error after timeout milliseconds (optional, default 10000). It does not report a time.window.dfcGame.openPlayerScreen(): void: Opens the player profile screen within the widget.window.dfcGame.openCharacterScreen(): void: Opens the character management screen within the widget.window.dfcGame.openStorageScreen(): void: Opens the storage/inventory screen within the widget.window.dfcGame.openQuestsScreen(): void: Opens the quests screen within the widget.window.dfcGame.close(): void: Closes the widget if it's currently open.window.dfcGame.initialized: boolean: A read-only property that indicates if the widget has been successfully initialized.window.dfcGame.isReady: boolean: A read-only property that becomes true 100 ms after the widget script runs. It means only that the API object exists and init() may be called. It says nothing about UI, auth or data.window.dfcGame.interactiveAt: number | null: A read-only property. The host performance.now() time (milliseconds from performance.timeOrigin) when the toolbar section buttons were first rendered enabled and accepted input. null until then, and while the critical auth/failure overlay is shown.window.dfcGame.readyAt: number | null: A read-only property. The host performance.now() time when the required startup data succeeded: auth/profile, widget Ready, domain cache, and the static and content dictionaries for the initial locale and English fallback. null until then, and after a required failure until a successful retry or restart(). Always interactiveAt <= readyAt.window.dfcGame.apiUrl: string: The current API URL being used by the widget (read-only).window.dfcGame.setLocale(locale: string): void: Sets the locale of the widget.window.dfcGame.locale: string | undefined: The current locale of the widget (read-only).window.dfcGame.appLangs: string[]: The available languages for the widget (read-only).These methods are intended for local runtime diagnostics in the lobby timed reward flow. They do not require reinitializing the widget, they reset automatically after window.dfcGame.restart(), window.dfcGame.destroy(), or a full page reload, and they do not change the widget's regular init configuration.
window.dfcGame.enableTimedRewardDebugLoop(): boolean: Enables a frontend-only timed reward claim loop in the lobby. Claim animation continues locally without backend claim requests, cooldown timers are ignored on the frontend, and the reward becomes immediately claimable for animation testing.window.dfcGame.disableTimedRewardDebugLoop(): boolean: Disables the timed reward runtime debug loop and restores the normal backend-backed claim flow.window.dfcGame.toggleTimedRewardDebugLoop(force?): boolean: Toggles the timed reward runtime debug loop. Optional boolean argument forces the target state.window.dfcGame.getTimedRewardDebugLoopState(): boolean: Returns the current runtime state of the timed reward debug loop.window.dfcGame.enableTimedRewardDebugLoop();
window.dfcGame.getTimedRewardDebugLoopState(); // true
window.dfcGame.disableTimedRewardDebugLoop();
The init function accepts a configuration object with the following optional properties:
| Property | Type | Description | Default |
|---|---|---|---|
hostElementSelector |
string | CSS selector for the HTML element where the widget will be rendered. | 'body' (appended) |
userCookieName |
string | Name of the cookie that stores the authenticated user's token. | 'user_token_dev' |
guestCookieName |
string | Name of the cookie that stores the guest user's token. | 'guest_token_dev' |
wikiUrl |
Record<string, string> | Map of wiki URLs per language (e.g., { ru: '...', en: '...' }). If omitted or empty, the link is hidden. |
undefined |
logoUrl |
string | URL for the logo in the widget's footer. If provided, the logo becomes a clickable link. | undefined |
settingsUrl |
string | URL for the host site's account settings page opened from the header avatar. | 'https://devf.dapp.expert/settings' |
onLoginClick |
function | A callback function to be executed when the user clicks the "Login" button. Overrides the default `window.dapp.openLogin` behavior. | undefined |
onSignupClick |
function | A callback function to be executed when the user clicks the "Sign Up" button. Overrides the default `window.dapp.openRegistration` behavior. | undefined |
onNavigate |
function | Host callback invoked by Meme Locator before its default navigation. Return false after your site handles the destination with its SPA router; otherwise the widget calls window.location.assign(url) in the current tab. |
undefined |
defightLink |
Record<string, string> | URLs of the DeFight landing page by locale. The widget renders the URL matching its current locale; invalid, missing, or incomplete values use the canonical DeFight landing page. | 'https://dapp.expert/dfc/widget-landing' |
dappApiUrl |
string | Base URL for Dapp (site) API, used by the Meme Locator. If omitted, apiUrl is used. |
undefined |
referralLinkPattern |
string | Referral link URL template. Must include {referralId} placeholder. |
undefined |
bugReportRecaptchaSiteKey |
string | Google reCAPTCHA v2 Checkbox site key for bug report form. | undefined |
svgSpritePath |
string | Path to a custom SVG sprite file. | (Internal path) |
locale |
string | Preferred locale for internationalization (e.g., 'en'). | Browser's default |
appLangs |
string[] | Array of available languages for the application. (e.g., 'en, ru') | ['en', 'ru'] |
languageIds |
Record<string, number> | Host-site numeric language ids keyed by locale code, sent as X-User-Language-Id on Meme Locator requests for the explicitly supplied locale (or the last setLocale() value) once normalized to its primary tag (ru-RU → ru) and listed in appLangs; translation loading does not affect it. An integer value overrides the built-in id for the same code; a non-integer value is ignored. When no supported locale was supplied or no id is mapped for it, the widget falls back to a numeric language_id cookie, otherwise sends no id; it never writes cookies. (e.g., { ru: 7 }) |
{ en: 1, ru: 2 } |
Note: runtime debug helpers such as window.dfcGame.enableTimedRewardDebugLoop() are not part of the init(config) payload. They are temporary console-driven switches for local animation debugging only.
The widget integrates with your site's authentication system by passing callback functions in the initialization configuration. You must provide `onLoginClick` and `onSignupClick` functions in the config object passed to `window.dfcGame.init()`.
window.dfcGame.init({
// ... other config options
onLoginClick: () => {
console.log('Host site: onLoginClick triggered');
alert('Host site: Login modal would open here.');
},
onSignupClick: () => {
console.log('Host site: onSignupClick triggered');
alert('Host site: Registration modal would open here.');
}
});
The widget will call these functions when the user clicks on the "Log In" or "Sign Up" buttons within the widget.
Provide onNavigate when the host site must handle a Meme Locator "Visit" request with its own SPA router. The callback receives the destination URL and context. Return false only after the host has handled the navigation; this prevents the default window.location.assign(url) fallback in the current tab.
The configuration property has the following TypeScript contract:
onNavigate?: (payload: {
url: string;
source: 'meme-locator';
title?: string;
type?: string;
itemSlug?: string;
targetName?: string;
targetGroup?: string;
}) => boolean | void;
window.dfcGame.init({
// ... other config options
onNavigate: ({ url, source }) => {
const target = new URL(url, window.location.origin);
if (source === 'meme-locator' && target.origin === window.location.origin) {
// Replace with the host site's SPA router API.
hostRouter.navigate(`${target.pathname}${target.search}${target.hash}`);
return false; // Host handled navigation; prevent the widget fallback.
}
}
});
When the callback does not return false, the widget uses window.location.assign(url). Use that fallback for destinations that the host router does not own.
The DFC Game Widget dispatches a custom widgetLoaded event each time its status becomes Ready outside the failure state. This happens after the initial auth check, the socket connection and a fixed 500 ms pause. It does not wait for the domain cache or translations, it repeats after every reconnect and re-init, and a late subscriber misses it. Do not use it, or the promise resolved by init(), as proof that widget data is loaded. For that, use dfc:widget-ready described below.
This event is particularly useful for controlling host-site elements, such as hiding a splash screen or preloader, that are displayed while the widget is loading.
document.addEventListener('widgetLoaded', () => {
console.log('DFC Widget status is Ready');
// Add your logic here to hide a splash screen, enable buttons, etc.
// For example:
// document.getElementById('my-splash-screen').style.display = 'none';
});
The event is a standard CustomEvent with bubbles: true and composed: true, meaning it will propagate up the DOM tree and traverse Shadow DOM boundaries, making it accessible from the main document.
Two milestones describe the page. Both are measured on the host performance.now() timeline (milliseconds from performance.timeOrigin), not as epoch time and not as time since init():
interactiveAt: the toolbar section buttons are rendered enabled and accept input. It is not set while the critical auth/failure overlay is shown.readyAt: the required startup data succeeded: auth/profile, widget Ready, domain cache, and the static and content dictionaries for the initial locale and English fallback. It is always sampled after interactiveAt. It does not wait for toolbar notifications, unopened screens, images or network idle.Both values are published on window.dfcGame before the matching document event is dispatched. The events are dfc:widget-interactive (detail { interactiveAt, readyAt: null }) and dfc:widget-ready (detail { interactiveAt, readyAt }). Each fires at most once per page, and dfc:widget-interactive always comes first. Events are not replayed to late subscribers, so read window.dfcGame.interactiveAt and window.dfcGame.readyAt instead. If a required dependency fails, readyAt stays null, no ready event fires and no error event is sent; a later successful restart() or retry records it.
document.addEventListener('dfc:widget-interactive', (event) => {
console.log('Interactive at', event.detail.interactiveAt);
}, { once: true });
document.addEventListener('dfc:widget-ready', (event) => {
console.log('Ready at', event.detail.readyAt); // ms from navigationStart
}, { once: true });
Use the controls below to configure and initialize the widget in the container at the bottom of the page.
Current Status: Checking...
Note: After changing auth state, you must Restart the widget to see the effect.
Uses Auth Token from Authentication State.
To prevent NG0908 errors on first load, always wait for the widget API to be ready:
<script>
document.addEventListener('DOMContentLoaded', async function() {
// Wait for widget API to be ready (recommended for production)
if (window.dfcGame && window.dfcGame.waitForReady) {
try {
await window.dfcGame.waitForReady(10000); // 10 second timeout
const widget = await window.dfcGame.init({
hostElementSelector: '#your-widget-container',
onLoginClick: () => {
// Your login logic here
console.log('Login clicked');
},
onSignupClick: () => {
// Your signup logic here
console.log('Signup clicked');
}
});
console.log('DFC Widget initialized successfully');
} catch (error) {
console.error('Failed to initialize DFC Widget:', error);
// Retry logic (optional)
setTimeout(async () => {
try {
await window.dfcGame.init();
console.log('DFC Widget initialized on retry');
} catch (retryError) {
console.error('Widget initialization failed on retry:', retryError);
}
}, 1000);
}
} else {
console.error('DFC Widget not available');
}
});
</script>
<script>
document.addEventListener('DOMContentLoaded', function() {
function initDfcWidget() {
if (window.dfcGame && window.dfcGame.isReady) {
// Widget API is ready, safe to initialize
window.dfcGame.init({
hostElementSelector: '#your-widget-container',
onLoginClick: function() {
console.log('Login clicked');
},
onSignupClick: function() {
console.log('Signup clicked');
}
}).then(function() {
console.log('DFC Widget initialized successfully');
}).catch(function(error) {
console.error('Failed to initialize DFC Widget:', error);
});
} else {
// Widget not ready yet, wait and retry
setTimeout(initDfcWidget, 100);
}
}
// Start checking for widget readiness
initDfcWidget();
});
</script>
window.dfcGame.isReady or use await window.dfcGame.waitForReady() before calling init()init() immediately after script load - this causes NG0908 errors