Pixel

Pixel Updates & Events

Server Updates & Events

Announcements

DEV Community

Game Analytics: The Events Every Mobile Game Should Track

The short answer Track a small, planned set of events in six groups: sessions, the first-launch funnel, progression, economy, monetization and technical health. Write them in a tracking plan before coding, name them consistently and attach parameters. With about twenty well-chosen events you can calculate retention, find where players quit, balance the economy and see why revenue rises or falls. Start from questions Events exist to answer questions. Write the questions first. Where do new players drop out in the first ten minutes? Which level is too hard? Are players running out of currency or sitting on piles of it? Which ad placement is used most? Do players who use a feature stay longer? Is the game stable on low-end phones? If an event answers none of your questions, do not add it. The core event list Group Event Key parameters Session session_start, session_end Session number, duration Onboarding tutorial_step Step name or number, time since install Onboarding first_level_complete Time since install Progression level_start Level, attempt number, character or loadout Progression level_complete Level, duration, score, stars, boosters used Progression level_fail Level, reason, progress percentage, attempt number Economy currency_earned Currency, amount, source Economy currency_spent Currency, amount, item, sink Monetization shop_opened Entry point Monetization purchase_started, purchase_completed, purchase_failed Product, price, currency, failure reason Ads ad_opportunity, ad_shown, ad_completed, ad_reward_granted Placement, type, network Engagement feature_used Feature name Engagement daily_reward_claimed Day in streak Engagement notification_opened Notification type Technical loading_time Scene, seconds Technical error Type, context Most analytics tools record installs, device model, country and app version automatically. The first-launch funnel The steepest loss of players happens in the first session, so instrument it most carefully. Fire an event at each step: app opened, loading finished, each tutorial step, first action, first win, return to menu, second level started. View these as a funnel. A large drop between two steps points to a specific problem: a long load, a confusing instruction, a forced sign-up. Fixing the worst step is often the cheapest retention gain available. See mobile game KPIs for what good retention looks like. Progression events Level start, complete and fail are the backbone for any level-based game. Completion rate per level shows difficulty spikes. Attempts per level shows frustration. Fail reason and progress show whether players lose at the start or one move from the end, which call for different fixes. Time per level helps content planning. Games without levels use equivalents: match start and end, quest accepted and completed, zone entered. See level design principles. Economy events Record every time a currency enters or leaves a player's balance, with the source or sink. This reveals: Inflation, when players earn far more than they spend. Starvation, when progress stalls for lack of currency. Which sinks players value. The effect of a balance change, by comparing before and after. This is essential for free-to-play games. See game economy design. Monetization events For purchases, track the whole path from shop opened to purchase completed, including failures with reasons. For ads, track the opportunity, the impression and the completed reward by placement. That tells you which placements players choose and where fill is poor. Background is in in-app purchase implementation, rewarded ads design and ad mediation. Naming rules One style everywhere. Lowercase with underscores is the common convention. Object then action. level_start, level_complete, purchase_completed. Parameters, not names. One level_complete event with a level parameter, not level_1_complete, level_2_complete. Stable names. Renaming an event breaks historical comparisons. Consistent units. Seconds, not a mix of second...

Powered by Readybot.io

**DEV Community** ## Game Analytics: The Events Every Mobile Game …

DEV Community

The Sample Passed. What Did We Actually Prove?

Why a clean control test can still leave a decision maker exposed By Manfredi Marrocco The report says every sampled access removal was completed on time. The dashboard turns green. A manager asks whether the company can now rely on its leaver process. There is a missing question: did the sample come from a complete list of leavers? If the test began with tickets already created in the identity system, it may have excluded precisely the cases where nobody created a ticket. Ten well-processed tickets can demonstrate that those ten tickets were well processed. They cannot, by themselves, establish that all departures entered the process, or that the same process worked in every subsidiary. This distinction has practical consequences. A control assessment does not merely collect proof that an activity happened; it establishes how far that proof can support a decision. The boundary depends on the control objective, the population, the test and the period examined. A pass without those boundaries can be more misleading than an explicit limitation. Return of the Obra Dinn as a decision lens In Return of the Obra Dinn, the player investigates a ship and reconstructs events through observation and deduction. The official description establishes that investigative premise. The connection to control assessment is the discipline of asking what an observation can support. It is not a claim that a fictional investigation follows an audit standard. The useful connection is the boundary of a deduction. A ticket constrains the account of a recorded departure; it cannot establish the complete departure population. The game offers a designed mystery. An organisation must also account for evidence that is unavailable and conclusions that remain unresolved. Start with the claim, not the screenshot Consider a fictional organisation, Northstar Distribution. Its policy says that relevant access for departing employees must be removed within a defined period after departure. The assessment team receives ten closed tickets, each with a timestamp and an apparent approval. All ten meet the organisation's internal deadline. The example is hypothetical: neither the deadline nor the sample size represents a universal requirement. What has been shown? For the ten selected records, the ticket system contains information consistent with timely completion. That is a useful observation. It is not yet the same as showing that every departure was captured, that all relevant accounts were disabled, or that an account could not be reactivated later. The claim can be broken into questions: Coverage: Were all in-scope departures identified, including contractors where the control applies? Execution: Were the required actions completed by the applicable deadline? Completeness of action: Did the actions cover the relevant systems and privileged accounts? Persistence: Did access remain removed, or did a later event restore it? Period and scope: Which entities, services and dates were actually examined? Each question calls for different evidence. A ticket timestamp may speak to execution. It is weaker evidence of coverage when the ticket list is the only source of the population. A screenshot of a disabled account may demonstrate its state at a particular time, but not necessarily when it changed or whether other accounts existed. NIST's definition of a security control assessment distinguishes correct implementation, operation as intended and the desired outcome against security requirements. Those are related but separate questions. NIST SP 800-53A provides tailorable assessment procedures and planning guidance; it is a US framework, and its use here is methodological guidance, not a claim that every organisation is legally bound by it. The population is part of the test A sample can only be interpreted against the population from which it was selected. If Northstar tests only identity-system tickets, its population is “tickets recorded in that system,” not automat...

Powered by Readybot.io

**DEV Community** ## The Sample Passed. What Did We Actually …

** Latest from PC Gamer **

YouTuber and comedian Ashens has 1,000 hours in Baldur's Gate 3 and reveals the worst retro game he's ever played: 'By the time you've hacked it to work, it's just no fun whatsoever'

The filmmaker and author of Terrible Old Games You've Probably Never Heard Of gives us a tour of his Steam library.

Powered by Readybot.io

** Latest from PC Gamer ** ## YouTuber and comedian …

DEV Community

豆包 Seed 2.1 API 接入 Tokuse:Pro / Lite / Turbo 价格、效果与选型指南

Tokuse 已经接入 ByteDance 豆包 Seed 2.1 系列的三个模型,并且统一提供 OpenAI 兼容接口。对正在控制 AI 成本的团队来说,这不是多了一个模型选项,而是多了一组价格梯度:同样一套代码,可以在 Pro、Lite、Turbo 之间按任务切换,把能力档位和成本档位分开管理。 本文基于 2026 年 11 月 16 日 Tokuse 线上模型目录,对比 doubao-seed-2-1-pro-260915、doubao-seed-2-1-lite-260915、doubao-seed-2-1-turbo-260628 的价格、适用场景和接入方式。所有价格以 Tokuse 定价页 的实时数据为准,采购前请重新核对。 一句话结论 模型 ID 输入 / 百万 Token 输出 / 百万 Token 协议 适合场景 doubao-seed-2-1-pro-260915 $0.8220 $4.1100 OpenAI、Anthropic 复杂推理、长文分析、质量优先的 Agent 步骤 doubao-seed-2-1-lite-260915 $0.1096 $0.3699 OpenAI、Anthropic 日常对话、摘要、抽取、分类、高并发自动化 doubao-seed-2-1-turbo-260628 $0.0876 $2.1900 OpenAI、Anthropic 超长输入、极短输出,输出 Token 必须严格受控 两个关键差异: Lite 是平衡型工作负载的成本底线。 在当前 Tokuse 价格下,它的输入和输出单价都比 DeepSeek Flash 低约 60% 和 66%。 Turbo 不是"更便宜的 Lite"。 它的输入单价最低,但输出单价约为 Lite 的 5.9 倍。只有输入很长、输出很短的任务才适合 Turbo。 Pro 是能力档,不是默认档。它适合 Lite 达不到质量线的那部分任务,而不是所有请求都走 Pro。 三个模型分别适合什么 豆包 Seed 2.1 的三个档位是按工作负载形态划分的,不是按一个跑分排序。 豆包 Seed 2.1 Pro 是这一系列的能力档。多步规划、工具调用、长文档分析、对指令遵循要求高的回答,应该优先在 Pro 上验证。它的输出价格是三档中最高的,所以适合"答错比 Token 更贵"的任务。 豆包 Seed 2.1 Lite 是平衡档,也是最值得作为默认选项的模型。客服、摘要、结构化抽取、打标签、分类、常规 Agent 步骤都可以先跑 Lite。$0.1096 的输入价和 $0.3699 的输出价,让高请求量场景的成本更可控。 豆包 Seed 2.1 Turbo 面向输入重、输出轻的任务。例如读取很长的上下文,最后只返回一个标签、一个 JSON、一条路由判断。它的输入价 $0.0876 是三档最低,但一旦生成长答案,$2.1900 的输出价会迅速放大账单。 实际策略可以很简单:默认 Lite,用真实提示词做评测;达不到质量线的意图升级到 Pro;只有输出长度确实受控的任务才用 Turbo。 一个真实工作负载的成本 只看单价容易误判。输出占比一高,账单结构就会变。 以 1 亿输入 Token + 2000 万输出 Token 为例,把豆包 Seed 2.1 和 Tokuse 上的两个 DeepSeek 模型放在一起比较: 模型 输入成本 输出成本 合计 豆包 Seed 2.1 Lite $10.96 $7.40 $18.36 DeepSeek Flash $27.40 $21.92 $49.32 豆包 Seed 2.1 Turbo $8.76 $43.80 $52.56 豆包 Seed 2.1 Pro $82.20 $82.20 $164.40 DeepSeek V4 Pro $123.20 $73.96 $197.16 在这个输入输出比例下,Lite 比 DeepSeek Flash 便宜约 63%。Turbo 因为输出单价高,反而略贵于 DeepSeek Flash。Pro 的成本接近 DeepSeek V4 Pro,符合能力档的定位。 换一个工作负载,排序会变: 工作负载 豆包 Lite 豆包 Turbo DeepSeek Flash 8000 万输入 + 400 万输出 $10.25 $15.77 $26.30 1000 万输入 + 5000 万输出 $19.59 $110.38 $57.54 长报告、代码生成、多轮对话这类输出偏重的工作,Lite 仍然是这组里最便宜的。Turbo 只有在输出占输入比例极低时才有优势。 缓存价格不能忽略 DeepSeek 提供缓存命中价格,Tokuse 的模型目录也暴露了对应的缓存倍率。按当前 deepseek-flash 价格,缓存命中输入约为每百万 Token $0.006,远低于未命中的 $0.274。 豆包 Seed 2.1 在 Tokuse 目录中的报价不包含缓存折扣假设。如果你的应用会反复复用同一段长系统提示词或 Agent 上下文,先测算缓存命中比例,再判断 Lite 是否一定更便宜。对于输出很小的任务,高缓存命中率的 DeepSeek Flash 有可能在总成本上反超 Lite;对于输出很重的工作,Lite 的低输出价仍然是决定因素。 这也是为什么应该用 成本计算器 和 Tokuse 的用量日志来验证,而不是只看一个首页单价。 用 OpenAI SDK 调用豆包 Seed 2.1 三个模型都接受 https://tokuse.com/v1 的 OpenAI 兼容 Chat Completions 请求。保留现有 SDK,只改 base URL 和模型 ID。 import os
from openai import OpenAI

client = OpenAI(
api_key=os.environ["TOKUSE_API_KEY"],
base_url="https://tokuse.com/v1",
)

response = client.chat.completions.create(
model="doubao-seed-2-1-lite-260915",
messages=[
{"role": "system", "content": "把客户意图抽取为 JSON。"},
{"role": "user", "content": "我被重复扣费了,需要退款。"},
],
)

print(response.choices[0].message.content)
Node.js 的写法相同: import OpenAI from "openai";

const client = new OpenAI({
apiKey: process.env.TOKUSE_API_KEY,
baseURL: "https://tokuse.com/v1",
});

const response = await client.chat.completions.create({
model: "doubao-seed-2-1-pro-260915",
messages: [{ role: "user", content: "总结这份合同。" }],
});
也可以直接发 HTTP 请求: curl https://tokuse.com/v1/chat/completions \
- H "Authorization: Bearer $TOKUSE_API_KEY" \
- H "Content-Type: application/json" \
- d '{
"model": "doubao-seed-2-1-turbo-260628",
"messages": [{"role": "user", "content": "分类:退款请求"}],
"temperature": 0
}'
也可以使用 Anthropic Messages 协议 豆包 Seed 2.1 在 Tokuse 上同时支持 Anthropic Messages 格式。把 base URL 设为 https://tokuse.com,路径由 SDK 处理: import os
import anthropic

client = anthropic.Anthropic(
api_key=os.environ["TOKUSE_API_KEY"],
base_url="https://tokuse.com",
)

message = client.messages.create(
model="doubao-seed-2-1-pro-260915",
max_tokens=1024,
messages=[{"role": "user", "content": "规划一个三步迁移方案。"}],
)

print(message.content[0].text)
如果现有系统已经用 Anthropic 兼容客户端跑 Claude,这条路可以让你不引入第二个 SDK 就完成豆包测试。完整的协议说明见 Anthropic Messages 指南。 流式、超时和常见错误 流式调用和其他 OpenAI 兼容模型一致: stream = client.chat.completions.create(
mo...

Powered by Readybot.io

**DEV Community** ## 豆包 Seed 2.1 API 接入 Tokuse:Pro / …

DEV Community

useEffect vs useLayoutEffect: Why the Tooltip Flashes, Then Jumps

Picture a tooltip that should sit above a button. For one frame it shows up at the top of the box, then it jumps into place. The measurement was right. It ran too late. useEffect let the browser paint the first, wrong position. The mental model: before the curtain, or after React updates the DOM, then the browser paints what the user sees. There is a gap between those two, like the moment before a curtain opens. useLayoutEffect runs in that gap, while the curtain is closed. useEffect runs after the curtain opens, once the user can already see the frame. Both take the same arguments: a setup function, a dependency list, and an optional cleanup. The only difference is when the setup runs. One update, from commit to paint 1. React writes the DOM — The new elements are in the document
2. useLayoutEffect — Measure and correct, still invisible
3. Browser paints — This is the frame the user sees
4. useEffect — Fetch, subscribe, log
The user only sees the frame after useLayoutEffect has finished. How it works useEffect is the one for work that talks to the outside world: a fetch, a subscription, a timer, a log line. The browser paints first, so the effect doesn't hold the frame up. The user sees the new UI, then the effect runs. useLayoutEffect is for the case where that first paint would be a lie. You need a number the browser only knows after layout, such as a height from getBoundingClientRect, and you need to change what's on screen with it. useEffect(() => {
const { height } = tipRef.current.getBoundingClientRect();
setTop(buttonBottom - height); // one frame at top: 0, then it jumps
}, [buttonBottom]);
Swap in useLayoutEffect and that setTop is flushed before the browser paints. React may render the tooltip twice, first at top: 0 and then at the measured spot. The user only sees the second render. That correction is also the cost. The code inside useLayoutEffect, and any state update it schedules, blocks the paint. A slow one delays the frame. The React docs say to prefer useEffect unless that blocking is the point. The dependency list works the same on both. It still decides when the effect re-runs, and a stale value is still stale. Timing doesn't change that. The rules are in useEffect dependencies. In practice Start with useEffect. Move to useLayoutEffect only after you've seen a flash. The flash shows up when you read layout and then write the screen: A tooltip or menu that must flip above or below, depending on the space left. A textarea whose height follows its content. Scrolling or focusing an element before the user sees it in the wrong place. Leave fetching, subscriptions, and logging on useEffect. They don't change the frame that's about to paint. Running them in useLayoutEffect makes that paint wait for work the user didn't need to wait for. Honest stakes: most components never measure the DOM. You'll want useLayoutEffect a handful of times, usually on something floating. Reaching for it to be safe makes the first paint slower. Wait until something flickers. Say it in an interview "useEffect and useLayoutEffect take the same arguments. useLayoutEffect runs after React commits DOM changes and before the browser paints, so you can measure layout and correct it without a visible flash. useEffect runs after the paint, so it doesn't block the frame. State updates inside useLayoutEffect are flushed before that paint. Default to useEffect, and switch only when the user would otherwise see one wrong frame." Cheat sheet useEffect useLayoutEffect When it runs After the browser paints After the DOM update, before the paint Blocks the paint? No Yes Use it for Fetch, subscribe, log Measure layout, then fix what the user would see A state update inside Shows up on a later frame Flushed before the paint The default This one Only after you've seen a flash TL;DR useLayoutEffect runs before the paint. useEffect runs after it. The layout version can measure the DOM and correct it before anyone sees the...

Powered by Readybot.io

**DEV Community** ## useEffect vs useLayoutEffect: Why the Tooltip Flashes, …

DEV Community

Spectral Clustering: Why the Eigenvectors of a Graph Laplacian Reveal Clusters

K-means is the first clustering method most people learn, and it is also the first one to fail in an instructive way. Give it two interleaving crescents, two concentric rings, or a long thin chain next to a dense ball, and it will cut straight through the structure you can see with your eyes. The failure is not a tuning problem. K-means assumes clusters are round blobs around a centre, and it measures closeness in raw Euclidean distance. When the shape of a cluster matters more than its centre, that assumption is wrong. Spectral clustering takes a different route. Instead of clustering points directly, it first turns the data into a graph, then asks a linear algebra question about that graph: which smooth, low-energy functions on the graph separate one region from another? The answer is given by the smallest eigenvectors of the graph Laplacian. Cluster in that eigenvector space, and crescents, rings, and chains suddenly become easy. This article explains what the Laplacian is, why its eigenvectors encode cuts, how the full algorithm works, and where it breaks down. From points to a graph Start with data points x1,…,xn . Spectral clustering does not work on the points themselves. It works on a weighted graph in which each point is a node and each edge weight wij measures how similar points i and j are. Similar points get a heavy edge, dissimilar points get a light edge or no edge at all. The clustering problem then becomes a graph partitioning problem: cut the graph into pieces so that few heavy edges are cut and each piece is internally well connected. The graph construction is the first real decision, and it matters more than most textbooks admit. Three common choices are: Epsilon neighbourhood graph: connect points closer than some radius ϵ . k-nearest-neighbour graph: connect each point to its k nearest neighbours, usually symmetrised by keeping an edge if either endpoint lists the other. Fully connected graph with a Gaussian kernel: connect everything, with weight decaying with distance. The Gaussian kernel is the usual default for a fully connected graph: wij=exp(−2σ2∣xi−xj∣2) Here σ is a scale parameter. Small σ makes the graph local: only genuinely near neighbours matter, and distant structure is ignored. Large σ makes the graph dense and blurs local detail. There is no universally correct σ , and a bad one can destroy the result before any eigenvectors are computed. In practice, a k-nearest-neighbour graph is often more robust than a fully connected Gaussian graph, because it adapts to varying density: a point in a sparse region still gets neighbours, and a point in a dense region is not swamped by weak long-range edges. Collect the weights into a similarity matrix W , with entries wij and zeros on the diagonal. Define the degree of node i as the total weight of its edges: di=j=1∑nwij Put the degrees on the diagonal of a matrix D . The unnormalised graph Laplacian is then: L=D−W That simple definition carries a surprising amount of structure. What the Laplacian measures Take any function f on the nodes, a vector with one value fi per point. The quadratic form fTLf has a clean expansion: fTLf=21i=1∑nj=1∑nwij(fi−fj)2 Read that carefully, because it is the whole intuition in one line. The quadratic form is a weighted sum of squared differences across edges. If f assigns similar values to strongly connected points, the sum is small. If f jumps across a heavy edge, the sum is large. So a function with small fTLf is smooth on the graph: it varies slowly inside well-connected regions and only changes where the graph is weakly connected. That is exactly what a cluster indicator should do. An ideal cluster indicator is constant inside each cluster and jumps only between clusters. If clusters correspond to weakly connected regions, the jump crosses only light edges, so the quadratic form stays small. Spectral clustering is, in this sense, a search for smooth functions on the graph. The Laplacian is symmetric and positive sem...

Powered by Readybot.io

**DEV Community** ## Spectral Clustering: Why the Eigenvectors of a …

DEV Community

Top Million Websites Saw Visits Fall 12.2% From Their 2022 Peak

Browser-based visits to the world’s top million websites were 12.2% below their 2022 peak by the third quarter of 2026, according to SparkToro’s analysis of Similarweb data. The finding matters because it describes a broad contraction in traffic flowing across the measurable open web, even while internet use continues to grow. For SEO teams, the result is less a verdict on any one channel than a reason to recalibrate. A decline in total available browser traffic can affect organic performance expectations, traffic forecasts and the way businesses evaluate search visibility. It also strengthens the case for measuring discovery beyond a single session or a single search result page. What SparkToro’s data found SparkToro’s open-web traffic analysis compares global browser visit data supplied by Similarweb over time. Its figures show that total visits to the top million websites had fallen 12.2% from their 2022 high by Q3 2026. The analysis also reported a 29.2% decline in visits per internet user. That per-user measure is important, but it should be read with care: SparkToro notes that revised internet-user estimates from DataReportal contributed to the change in the calculation. At the same time, the relative distribution of visits among the largest sites did not shift dramatically. The combined share going to the top 1 to 10 sites was roughly 33% in 2021, while sites ranked 11 to 100 accounted for about 36%. Those shares had moved only minimally by Q3 2026. Measure Observed finding What it indicates Visits to the top million websites 12.2% below the 2022 peak by Q3 2026 The overall browser-based open-web traffic pool was smaller than at its recent high. Visits per internet user Down 29.2% Per-user browsing declined in the analysis, though revised user estimates affect this metric. Share held by the largest sites Minimal movement from 2021 through Q3 2026 The largest websites remained disproportionately important rather than losing substantial share. Search Engine Journal’s coverage of the findings similarly emphasizes that the data concerns a global shift in browser traffic, not a measured change in paid advertising activity. A smaller traffic pool is not proof of one cause It is tempting to assign the decline entirely to AI-generated answers, zero-click searches or changes in Google Search. Those forces may be relevant to how people discover information, but this dataset does not isolate their impact. The released analysis is global, has no regional breakout and measures browser activity rather than app traffic. It also does not provide device-level detail in the supplied findings. As a result, it cannot show whether a particular country, industry, device type or search feature caused the observed change. That distinction matters. People can spend more time in apps, social platforms, messaging services and other closed environments that are not represented in browser-based open-web measurements. Changes in how internet users are counted also affect per-user comparisons. The data supports the conclusion that open-web browsing has weakened at a broad level. It does not establish a universal explanation for every website’s traffic decline. What the stable top-site share means The figures do not suggest a major redistribution of browser visits away from the web’s largest destinations. Instead, they indicate that the total volume of visits fell while the leading sites retained much of their collective share. For smaller businesses, publishers and ecommerce sites, this can make organic growth more difficult. Competing for demand remains necessary, but a rising position in search results may not produce the same number of visits it would have when the overall click pool was larger. A traffic-only view of SEO can therefore conceal real gains in rankings, visibility or qualified discovery. This does not mean smaller sites cannot win. It means they need a clearer view of where attention begins, where it goes next and which outcomes ...

Powered by Readybot.io

**DEV Community** ## Top Million Websites Saw Visits Fall 12.2% …

DEV Community

How I built a 1.8-second B2B Lead Scraper & 18-Signal Telemetry Auditor (Zero Headless Chrome)

Most website audit and B2B lead enrichment tools rely on heavy Headless Chrome queues that take 30–45 seconds per domain and cost hundreds of dollars a month in server overhead. I wanted to build an instant B2B prospecting and technical audit engine for web design, SEO, and PPC agencies that executes in under 2 seconds at the edge for £0 server cost. Here is the live platform running on Cloudflare Workers: 👉 https://leakradar.leakradar.workers.dev (If you want to test the locked Pro features—including the 250-domain Bulk CSV Scraper, Contact Vault, and White-Label Client Reports—click "Unlock Pro" in the top right and enter the 4-day developer key: VIP-4DAY) What It Does in ~1.8 Seconds When you enter any domain (or hit the JSON API), the Worker fires parallel asynchronous fetch() streams from the nearest Cloudflare PoP across /, /contact, /contact-us, and /about: 18-Signal DOM & HTTP Telemetry Inspection: Ad Pixels: Meta/Facebook Pixel (fbevents.js), TikTok Pixel, LinkedIn Insight Tag, Google Ads Conversion tags. Analytics & Enterprise Stack: GA4, Google Tag Manager, Segment, Tealium, Hotjar, Microsoft Clarity, OneTrust. Conversion Architecture: Live Chat widgets (Intercom, Crisp, Tidio, Drift, Zendesk), CRM/Booking embeds (HubSpot, Calendly, Klaviyo), Lead forms, and JSON-LD application/ld+json schema. Edge & Security: Measures live Time-To-First-Byte (TTFB ms), inspects strict-transport-security (HSTS), and detects CDN edge headers. Cloudflare data-cfemail Hex Decryption + Contact Scraping: Extracts verified corporate @domain emails, tel: phone lines, and social profiles across subpages. Includes a bitwise XOR hex decoder that automatically decrypts Cloudflare's data-cfemail email obfuscation on the fly:
javascript
function decCf(html) {
let out = [], r = /data-cfemail="([0-9a-fA-F]+)"/g, m;
while ((m = r.exec(html)) !== null) {
let s = m[1], k = parseInt(s.substr(0, 2), 16), e = "";
for (let i = 2; i < s.length; i += 2)
e += String.fromCharCode(parseInt(s.substr(i, 2), 16) ^ k);
if (e.includes("@")) out.push(e.toLowerCase());
}
return out;
}

Powered by Readybot.io

**DEV Community** ## How I built a 1.8-second B2B Lead …

DEV Community

A Practical Guide to Choosing Between a VPS and Cloud Hosting

“Cloud” and “VPS” are sold as identities. In practice they are different ways to rent a computer and a network, with different bills, failure modes, and homework. The wrong choice is not usually “we picked VPS instead of AWS.” It is “we picked a topology nobody on the team can operate at 11pm.” Palmate Solutions’ cloud and DevOps work is Linux, Docker, reverse proxies, backups, and pipelines you can explain. We keep a capable VPS when it is sufficient. We do not migrate a straightforward business app into a maze of managed services without a reason. If you are evaluating how to run an independent instance, start with securing a Linux production server. This article assumes you have outgrown “one PHP folder on a panel” and are choosing how to run an application you actually own. What people mean by VPS A virtual private server is a virtual machine with a committed slice of CPU, RAM, and disk. You get SSH, a Linux userspace, and the obligation to patch it. Providers vary: some are a hypervisor in a well-run data centre; some are a control panel and a hope. You typically pay a flat monthly price. You operate the guest. Firewalls, users, TLS, database, backups, and deploys are yours unless you buy them as extras. That is the point: few surprises, few usage-based invoices, full control of what runs. Failure is usually the whole box. Disk fills, kernel lockup, provider host issue, or a botched upgrade. High availability means a second machine, replication, and a failover story — not a checkbox labelled “cloud.” A VPS is a strong default for a single business application, a modest traffic shape, and a team that can SSH safely. Many Indian SMEs run production this way for years when backups are tested and deploys are not “edit live over FTP.” What people mean by cloud hosting “Cloud” here means a platform of APIs: virtual machines plus load balancers, managed databases, object storage, secrets, autoscaling groups, and a bill that moves with usage. You can run one VM on a cloud provider and still be “on the cloud” in marketing. You are not using the platform until you use the platform. You operate a graph of services. That is powerful when you need independent scale, regional failover, or a managed Postgres with point-in-time recovery you do not want to run yourself. It is expensive and noisy when you only needed a reverse proxy and a container. Failure is partial until it is not. A managed database outage, an IAM misconfiguration, or a region event can look like “the site is up but login is dead.” Debugging requires knowing which product owns which hop. Cost is a product. Egress, load balancer hours, NAT gateways, and log ingestion surprise teams who compared a ₹x/month VPS to “the free tier.” Cloud is not automatically cheaper at small scale. It can be cheaper at large or spiky scale if you actually turn machines off and right-size. Compare the jobs, not the logos Job VPS-shaped answer Cloud-shaped answer Predictable monthly cost Easy Requires tagging, budgets, and discipline One app, one database, business-hours load Compose on one or two VMs Often overkill Need a second region tomorrow Painful, manual Designed for it, still not free Managed backups with restore drills You build the drill Vendor helps; you still drill Compliance questionnaires asking for vendor lists Short list Long list of subprocessors Team with one engineer Fewer moving parts More IAM and billing surface The interesting row is who can restore. A backup you have not restored is a rumour, on any provider. Cloud snapshots do not excuse you from a restore drill. VPS cron dumps to a bucket do not either. Uptime is a budget, not a feeling Vendors advertise 99.9% and 99.99% as if they were features you install. Those percentages are allowed downtime over a year, plus a pile of exclusions in the SLA. Convert them to minutes before you pay for redundancy you will not operate. The uptime calculator does that conversion. Pair it with understanding 99.9% vs 99.99% uptime...

Powered by Readybot.io

**DEV Community** ## A Practical Guide to Choosing Between a …

DEV Community

Access Control and Secrets Hygiene for Small Teams

Most small-company security incidents are not cinematic zero-day exploits orchestrated by foreign state actors. They are mundane, preventable operational oversights: a departed contractor who still holds an active SSH key to the production server, a live Stripe secret key pasted into a public Slack channel, or a shared [email protected] login with no multi-factor authentication. Palmate’s cloud and DevOps baseline is built around named identities, explicit secrets boundaries, and a verifiable joiner/leaver workflow. This is not an abstract enterprise IAM manual. For securing the host operating system, see how to secure a Linux production server. For structuring API authentication, review our guide on OAuth vs API keys for business integrations. If you suspect a credential has already leaked, consult what small companies should do after a security incident. The Identity Baseline: One Human, One Account Shared credentials are the enemy of security governance. The moment two engineers share an SSH login or a database management password: Audit trails become fictional: You cannot determine whether an anomalous record deletion was legitimate maintenance or an unauthorized breach. Offboarding becomes theatre: Revoking access for a departing employee forces you to change credentials across six shared systems and distribute the new passwords to everyone else—disrupting ongoing work. Core Identity Rules Individual named accounts: Every developer, operator, and contractor receives their own dedicated login across GitHub, AWS, cloud consoles, and database bastions. Hardware-enforced MFA: Mandatory multi-factor authentication on root identities (email provider, Git host, domain registrar, and cloud hosting provider). Use authenticator apps (TOTP) or hardware security keys (FIDO2)—never SMS verification. Role-based least privilege: Frontend contractors do not need read access to production databases. Backoffice operators do not need root access to VPS hosts. Access should be scoped strictly to current sprint deliverables. Secrets Are Not Configuration: The 4-Tier Secrets Taxonomy Treating API secrets as ordinary environment variables causes them to bleed into client bundles, log files, and bug trackers. Group your project values into four explicit tiers: Category Typical Examples Safe Storage & Exposure Leak Impact Tier 1: Public Config Site URLs, analytics IDs, feature flags. Committed in code, client-side bundles. None (intended for public web browsers). Tier 2: Sensitive Config Internal microservice URLs, non-sensitive port numbers. Environment files, server configs. Internal network mapping and recon. Tier 3: High-Risk Secrets Transactional email keys, SMS gateway tokens, OAuth secrets. Secret managers, runtime injection. Spam dispatch, SMS fraud, account takeover. Tier 4: Crown Jewels Production database root credentials, payment processor secret keys, master signing certificates. Encrypted vaults, restricted IAM, zero-developer access. Total database exfiltration, direct monetary theft. You can inspect non-production tokens using our browser-based JWT decoder when verifying claim signatures. Never paste production secrets or live authorization headers into third-party web utilities. Comparing Secret Storage Mechanisms Small teams often struggle with where to store secrets without slowing down daily delivery. Here is how modern approaches compare: 1. Plain .env Files on the Host The Good: Trivial to implement; supported natively by Docker Compose and language runtimes. The Risk: Files can be accidentally committed to Git, copied into backup archives, or read by compromised processes. Recommendation: Acceptable for local developer machines only. For production hosts, restrict permissions strictly: chmod 600 .env owned by root. 2. Encrypted Repositories (SOPS / git-crypt) The Good: Secrets are encrypted at rest using KMS or PGP keys; secret history is versioned alongside code. The Risk: Merge conflicts in encrypted blobs can be diff...

Powered by Readybot.io

**DEV Community** ## Access Control and Secrets Hygiene for Small …

DEV Community

Wild Shift Devlog #4: Don't lose your run

Fourth update on The Debugger 0x03: Wild Shift, my GitHub Game Off 2026 entry (theme: SHIFT). Devlog #1 covered the register and the shift, Devlog #2 the first two bosses, Devlog #3 the final boss and the ending. This post is a mirror of the fourth devlog on itch.io. You can also play the current build in the browser on the game page. The game is complete, and now it has to survive other people. Since the last devlog The Debugger 0x03: Wild Shift got its audio plumbing, a final sound pass, save and resume, a gamepad, a practice mode and a few quality-of-life switches. Less console.log("boss"), more return 0; with a nice exit code. Sound (Epic 7, part 1) Music plumbing. Each fight now has its own track and the game crossfades into it. In phase 3 a glitched variant of the track fades in step with the original, and while Breakpoint is active the music drops into a muffled loop, like someone put a pillow on the speakers. Dying and retrying is an instant cut, so you never wait for a song to catch up with your second attempt. Heads up: the tracks you hear right now are placeholders. They are generated loops that only prove the wiring works. I'm composing the real ones in BeepBox, and they'll drop in under the same file names with no code change. Please don't judge the music yet. Final SFX pass. 15 sound effects, all generated procedurally by a small script, so they are mine by construction. The two shift directions now have distinct clicks, every boss attack has its own tell cue (a sound before a hit, same rule as the visual tells), and the duck got a proper squeak. Don't lose your run (Epic 7, part 2) Save and resume. The game remembers the highest boss you reached. The title screen resumes from there, and [N] starts a new run. Mute is remembered too. If saving isn't available (private window, blocked storage), it silently falls back to a normal session. [B] debug build. An optional assist toggle for people who want to see the story: 8 HP instead of 5, a shorter Breakpoint cooldown, and slower boss tells. Damage numbers stay the same. It's saved, and it's named after the only thing a debugger really wants. Gamepad. Stick or d-pad to move, face and shoulder buttons for the actions and shifts, the right trigger for Breakpoint, Start to pause. Any button advances the title, intro and ending screens, so you can play start to finish without touching the keyboard. [F] fullscreen. On the title and the pause screen, by key, click or pad. Practice (Epic 7, part 3) The title screen now has [P] practice: a fight against the / test / dummy with a hit log and a frames N counter, available in every build. You can cycle through loadouts with L, so you can try a combo before you have earned it in the run. It writes nothing to your save and has no intro. Esc takes you back to the title. The title screen with the new options. ([N] new run shows up once you have a save.) Practice mode: the / test / target, the hit log and the frame counter. The pause screen now has mute, debug build and fullscreen rows. Measuring the run The last code story is a small playtest harness: the game prints [metrics] lines with the time to the first shift, the time and deaths per boss, and a total for a full run. No gameplay value changed, it only counts. I'll use it to tune what the numbers say is too hard or too easy, instead of what I feel at 1 a.m. I also added a build-size check to CI (the web build must stay under 32 MB), and the README, credits and this page's copy are done. The credits include mumble-speech, my own library, for the duck's voice. How it's made Same as before: I'm the director and the playtester, AI agents (Claude) write the code from specs I approve with the BMAD Method, and every story is a pull request with code review and automated tests. The test suite went from 112 to 121 test files. Everything is public in the GitHub repo. Next up What's left is the part only people can do: a full-run playtest, a browser check (Chrome, Firefox, Safari)...

Powered by Readybot.io

**DEV Community** ## Wild Shift Devlog #4: Don't lose your …

DEV Community

How to Tell If Your Mac App Has Been Cracked

Search your app name plus "crack", "cracked" or "free download" on Google, warez and torrent sites, and GitHub. Inspect a found copy with codesign -dv --verbose=4 and spctl -a -vv without launching it, then compare Team ID and cdhash to your release. https://fortifie.xyz/cracked runs the listings search faster, a search of public listings, not proof. This guide is for the developer who published the app, not for someone seeing a Gatekeeper warning. A cracked copy can appear on a warez site, a torrent index or GitHub without showing up in your analytics. How to check whether your Mac app has been cracked Start with a search, not a download. On Google, query your app name plus "crack", "cracked", "free download" or "dmg", and quote the name if it is generic. Repeat those queries on Mac warez sites and torrent indexes, then search GitHub for the app name, your bundle ID, or a distinctive Info.plist string. If a listing looks like your app, download the archive to an isolated folder. Do not launch the .app or drag it into /Applications. Mount a disk image if you have to, then point the tools at the bundle inside. codesign -dv --verbose=4 /path/to/Suspected.app
The codesign(1) man page describes --display (-d) as printing signature information; higher verbosity produces more fields. At --verbose=4 look for Identifier (usually your CFBundleIdentifier), TeamIdentifier (your Apple Developer Team ID), CDHash (the code directory hash for that architecture), and Authority (the certificate chain, typically Developer ID Application on a direct-distribution release). Compare TeamIdentifier and CDHash to the same output from the build you shipped. Apple's TN3126: Inside Code Signing: Hashes explains that the cdhash uniquely identifies the signed code. Matching values mean an unmodified copy of that signed build. A missing or ad hoc signature, or a different cdhash on a bundle that still looks like your app, can mean a patched or re-signed copy. For a universal app, codesign --display reports the native architecture of the Mac you are using, so check each slice with --arch arm64 and --arch x86_64. Display does not fully prove the signature is intact. The man page notes that --display is not a complete verification, and that --verify does not apply Gatekeeper or other OS policy. Also run: codesign --verify --deep --strict --verbose=2 /path/to/Suspected.app
spctl -a -vv /path/to/Suspected.app
spctl --assess (-a) asks the system policy subsystem whether the file would be allowed to run. The default type is execute, and verbose output typically includes accepted or rejected plus a source= line such as Notarized Developer ID or no usable signature. This is a policy check, not the same as opening the app. See Apple's TN3161: Inside Code Signing: Certificates for Team IDs, codesign --verify, and syspolicy_check. https://fortifie.xyz/cracked is a free search of public listings for your app, not proof. Don't run the cracked copy Treat an untrusted copy as malware until you have a reason not to. Warez installers often carry unrelated payloads. Your release records, plus the signature and file comparison below, can confirm the listing. codesign and spctl read the bundle and its signature; they are not the same as launching the app from Finder. For more isolation, inspect the copy in a virtual machine with no development keys or customer data, or just read the signature, Info.plist, resources and hashes. Confirm it's your build Match the version and the files Compare CFBundleShortVersionString, CFBundleVersion and CFBundleIdentifier in the copy's Info.plist to the release you shipped. Then compare file hashes for the main executable and, if you still have it, the shipping archive. An unmodified leak matches your release exactly: same cdhash, same Team ID, same file hashes. A patched crack will not, because the binary has changed, so also compare the bundle ID, version, icons and other resources. Record where and when you found it Keep the URL, the ...

Powered by Readybot.io

**DEV Community** ## How to Tell If Your Mac App …

DEV Community

WARN Act and Layoffs in Pharmaceuticals and Biotech — What Drug and Biotech Workers Should Know

Drug and biotech companies rarely announce layoffs the way a factory closure does. The cuts arrive as pipeline pivots, post-acquisition integrations, and cash-runway restructurings — and when they are big enough, they show up as WARN notices. Five recent pharmaceutical and biotech filings in the Layoff Atlas registry cover 526 workers, from an 88-person research institute in Los Angeles to a 205-person generic-drug operation in New York. These are reported plans, not confirmed job losses — filings can be amended, delayed, or cancelled before the effective date. The recent filings The five filings span California, New York, New Jersey, and Maryland: Ellison Medical Institute, Los Angeles, California — 88 workers. The cancer research and biotechnology institute filed notice on November 4, 2026, for 88 permanent job cuts effective January 3, 2027, at its Exposition Boulevard campus — exactly 60 days' notice. Crinetics Pharmaceuticals, San Diego, California — 78 workers. The endocrine drug developer's cuts take effect January 4, 2027, following Vertex Pharmaceuticals' $10 billion acquisition, which closed September 1, 2026. The registry listing originally carried a mistyped 2026 effective date; trade reports confirm January 4, 2027. InvaGen Pharmaceuticals, Long Island, New York — 205 workers. Two sites: 160 workers in Central Islip and 45 in Hauppauge, both noticed August 28, 2026, and effective November 27, 2026 — 91 days' notice, both permanent layoffs. Teva Pharmaceuticals USA, Fairfield, New Jersey — 61 workers. Effective February 1, 2027, filed with the New Jersey Department of Labor and Workforce Development. The notice date is unavailable in the record, so the notice period cannot be checked from the filing alone. Pharmaceutics International, Hunt Valley, Maryland — 94 workers. Notice published October 30, 2026, effective December 29, 2026 — exactly 60 days. The company is listed as a Jabil Inc. company. A sixth filing shows the other end of the scale: DesigneRx Pharmaceuticals in Vacaville, California, filed a 7-worker notice effective November 15, 2026 — far below the federal thresholds, a reminder the registry records what employers file, not only qualifying mass layoffs. Why pharma layoffs look different Pharmaceutical layoffs follow the drug-development cycle more than the business cycle. Three patterns show up again and again: Post-acquisition integration. Crinetics is the clearest recent example: Vertex completed a $10 billion acquisition on September 1, 2026, and the 78 San Diego cuts followed as the two companies combined operations. Acquired companies' corporate functions — finance, IT, and administrative roles — are usually the first to go. Pipeline pivots. When a trial fails or a program is deprioritised, the team behind it is cut. Clinical-stage biotechs run on cash runway, and a restructuring that extends that runway by a few quarters is often the stated reason. Commercial restructuring. Larger drugmakers cut sales forces when a product line is reorganised. Industry trackers counted 90 biopharma workforce-reduction events in 2026, covering more than 27,446 roles — mostly global announcements, not US WARN filings. The notice period depends on the state The federal WARN Act generally requires employers with 100 or more full-time employees to give 60 days' notice of a qualifying mass layoff or plant closing. But the states where pharma concentrates add their own rules, and the recent filings show all three in action: California requires 60 days' notice from employers with 75 or more employees — a lower threshold than the federal law. Ellison's 60 days and Crinetics' roughly 62 days both clear it. New York requires 90 days' notice from employers with 50 or more employees. InvaGen's 91 days clears that bar by a single day. New Jersey requires 90 days' notice, and its law also mandates severance in covered layoffs. Teva's missing notice date means the timing cannot be verified from the public record — a gap wor...

Powered by Readybot.io

**DEV Community** ## WARN Act and Layoffs in Pharmaceuticals and …

DEV Community

Writing a comparison page that says 'not affiliated': honest competitor mentions for SEO

I needed a page that would rank for a search term people actually type: the name of a big, well-known downloader. My own site is small and new, and nobody searches for its name yet. People do search for the big names, though, and for alternatives to them. So I built a comparison page that names the competitor, explains what my tool does differently, and carries the words "not affiliated" in plain sight. The idea sounds like a trick. It should not be one. The page only works if it is honest, because a comparison page that lies about a competitor is the fastest way to lose a visitor's trust. Here is how I approached it. Name the competitor, then stop selling The first decision is which name to target. I picked the biggest tool in my niche, the one whose name people type when they want to download a TikTok video. The page title and H1 carry that name next to the word "alternative", which is what people search for when the big tool is down, slow, or full of pop-ups. Then I made a rule for myself: the page may mention the competitor, but it may not claim anything about them I cannot verify. No "they sell your data". No "they are unsafe". No invented weakness. If I cannot prove it, I do not write it. What I can say, truthfully, is what my tool does: no sign-up, no watermark games, the formats labelled honestly. That is the comparison. My tool against a standard, not my tool against a straw man. The "not affiliated" line is not decoration Every comparison page I wrote carries a short line near the top: we are not affiliated with, endorsed by, or connected to the named service. I put it there for two reasons. The first is legal common sense. Using another brand's name to describe what your own product does is nominative use — the same way a repair shop can say "we fix iPhones" — but that only holds while you are genuinely describing, not pretending to be them. The disclaimer makes the relationship clear to a visitor in one glance. The second reason is trust. A visitor who lands on a page that names a famous tool wants to know immediately whether they are on the real site or a copy. The honest answer — no, this is a different tool, here is what it does — is the only answer that keeps them reading. If they feel tricked, they leave. The table has to be true The middle of the page is a simple comparison table: feature, them, us. I keep the rows to things I can check in a minute. Does it need an account? Does it work on a phone browser? Does it label audio honestly instead of promising an MP3 that does not exist? Each row is a fact, not an opinion, and I leave out any row where I would have to guess. I also wrote the limits of my own tool into the same page. If a format tops out at 360p with sound, the page says so. If a platform's links sometimes fail, the page says that too. That sounds like bad marketing, but it is the reason visitors stay: the page reads like it was written by someone who actually built the thing, because it was. Why this helps search at all Search engines do not reward the word "alternative" on its own. They reward pages that answer the question behind the search. Someone typing a big brand's name plus "alternative" is asking: is there something simpler, and can I trust it? A page that names the brand honestly, disclaims the connection, shows a true table, and admits its own limits answers that question in full. That is the whole technique. There is no cleverness to it, which is the point. A comparison page is a trust exercise dressed up as SEO, and the SEO only works if the trust part is real. I built the page on ramrom.io, where the TikTok downloader it describes actually runs, so anyone reading it can try the tool in the same visit and judge for themselves whether the comparison was fair. That is the test I keep coming back to: if the page cannot survive the visitor trying the thing, the page is not finished yet.

Powered by Readybot.io

**DEV Community** ## Writing a comparison page that says 'not …

DEV Community

How to verify a J-cut or L-cut in an exported MP4

Someone asks for a small revision to an interview. “Let me hear the answer, but stay on the listener for another half second.” The new MP4 sounds plausible. How do you tell whether the editor held the picture or slid the entire voice track? We made three 5.75-second reference exports at Valmera from the same exchange in the Sintel trailer. You can download all three and run the checks below. The reference renders use FFmpeg. The dialogue is the control: every version has the same decoded audio. File Audio edit Picture edit Straight cut 2.625 s 2.625 s J-cut 2.625 s 3.250 s L-cut 2.625 s 2.000 s Listen to the first word of the answer The line is “I'm searching for someone.” The audio edit occurs at 2.625 seconds. The first word comes around 2.8 seconds. That gap matters in an editing brief. “Hold for half a second after the first word” and “hold for half a second after you change audio takes” give different picture edits. Pause each file at 2.917 seconds. The straight cut has moved to a wide view. The J-cut still shows the close-up while the answer is underway. Now step back to 2.125 seconds. The L-cut shows the dark opening of the incoming shot while the question is still audible. That darkness is present in the source trailer. Compare the sound in the files If you control the export, encode the approved audio once and mux it into each picture version. Decode the audio to the same PCM format before comparing the files: for cut in straight j-cut l-cut; do
printf '%s ' "$cut"
ffmpeg -v error -i "$cut.mp4" -map 0:a:0 \
- c:a pcm_s16le -f hash -hash sha256 -
done
All three hashes match. The MP4 file hashes differ because their pictures differ. If an editor re-encodes audio for each export, a different PCM hash on its own does not tell you whether speech moved. Compare the timing of a short waveform passage before the join and again after it. Our source check compares seven 100-ms windows, including one on either side of the audio edit. See the measurements and exact file hashes. Check the picture against the source clock At 24 fps the straight cut switches takes at output frame 63, counting the first frame as zero. The J-cut switches at frame 78. The L-cut switches at frame 48. When the second take is visible, its source frame is the output frame plus 90. At output frame 70 the straight cut therefore shows source frame 160, while the J-cut still shows source frame 70. You can extract that moment without relying on a player's rounded time display: ffmpeg -v error -i j-cut.mp4 -vf "select=eq(n\,70)" -frames:v 1 frame-70.png
For your own interview, check one later word where the new speaker's mouth is visible. An editor can place the first transition correctly and still slip the rest of the sentence. Download the source, rebuild script and trial brief. For a separate example produced through Valmera, the four-second B-roll edit changes the picture on the word “green” while the presenter keeps speaking. Watch the recorded edit. Footage from Sintel, © Blender Foundation, CC BY 3.0. Valmera trimmed, resized and rearranged the excerpt and extracted the comparison frames. This tutorial was prepared with AI assistance.

Powered by Readybot.io

**DEV Community** ## How to verify a J-cut or L-cut …

DEV Community

Fusion splice loss: what the 0.03 dB on the splicer screen actually means

Fusion splice loss: what the 0.03 dB on the splicer screen actually means Part 8 of the series "Data center field notes" — field notes from real break-fix work. The splicer finishes the arc, the screen shows 0.03 dB, and the instinct is to call it good and move on. That number is not a measurement. It is the splicer's estimate of the loss, judged from the fiber image: how well the cores aligned, how clean the cleaves were. The real measurement comes later, on the OTDR trace or the span test. The estimate is still useful, but only if you read it the right way: against the loss budget for that span, not against a number you memorized, and with a clear rule for when to cut the splice and do it again. What the splicer actually estimates A fusion splicer does not measure light passing through the joint. It looks at the two fiber ends — core alignment, cleave angle, any chips or dirt on the end-face — and estimates the loss that joint should cause. A clean, square cleave with the cores dead-on gives a low estimate; a chipped cleave or a slight offset gives a higher one. That is why the estimate can change when you re-splice the same two fibers: nothing about the fiber changed, only the quality of the ends you presented to the arc. Treat the number as a screen at the tray, not as the record. The number that goes in the ticket as proof is the OTDR loss step or the span test, measured after the splice is protected and the tray is closed. This is the read I use after 200+ splices — single-mode and multimode, stripped, cleaned, and cleaved by hand, fused, protected in trays and enclosures, and validated with Fluke testing and OTDR and VFL checks. Read it against the budget, not against a universal number There is no pass/fail number for a single splice. The span's loss budget is the pass/fail line: add up the fiber attenuation for the distance, the connector losses, and every splice on the span, and compare the total to the budget. A 0.08 dB splice can be fine on a short span with budget to spare and a fail on a long span that is already near its limit. The same estimate means different things on different jobs, which is why a tech who memorizes "0.05 is good, 0.10 is bad" will pass splices that fail the span and re-do splices that were fine. Before you start splicing, know the budget for the span and how much of it is already spoken for by the other splices and connectors. Then each estimate gets judged against what is left. The re-splice decision: cleave first, always When the estimate comes back high against the budget, the first suspect is the cleave, not the splicer. Cut the splice, and inspect both ends before you touch anything else: cleave angle, chips on the edge, dirt on the end-face. Then re-strip, clean, and cleave both fibers and re-fuse. In most cases the second estimate drops sharply, because the first cleave was the problem. If the estimate stays high after a clean re-cleave, stop burning splices on the same joint and widen the check: are the two fibers the same type — single-mode to single-mode, multimode to multimode, same core size? Is the alignment actually seating, or is the fiber slipping in the holder? Are the electrodes worn, giving a weak or uneven arc? A high estimate that survives a good re-cleave is the splicer telling you something about the fiber or the machine, and re-fusing the same ends a third time will not fix it. Single-mode vs multimode: what "good" looks like The estimate behaves differently by fiber type, and so does the proof. On single-mode, the core is 9 microns and alignment is everything — a small offset is a real loss, so the estimate is sensitive and the OTDR will show a clean loss step at the splice point. On multimode, the core is 50 or 62.5 microns and the splice is more forgiving of alignment, but the estimate is also less precise, and the OTDR trace can show a gainer — a step that looks like gain rather than loss — depending on which direction you shoot the trace. That is why a multi...

Powered by Readybot.io

**DEV Community** ## Fusion splice loss: what the 0.03 dB …

DEV Community

Want to build a browser extension? If you know JavaScript, you’re already most of the way there.

Browser extensions are one of the most underrated things a web developer can build. They’re small, useful, and you can ship one fast. Here’s what helped me understand them. What an extension is made of: manifest.json: The config file. It defines the name, version, permissions, and which scripts run where (use Manifest V3 for new projects) Content scripts: JavaScript that runs inside web pages, so you can read or change the page Background service worker: Handles events and long-running logic behind the scenes Popup / options page: The UI users see. It’s just HTML, CSS, and JS, and you can build it with React Storage and messaging APIs: Save user settings and let the different parts talk to each other Tips for getting started: Start with a tiny idea, like a button that changes a page’s style or saves a note Ask only for the permissions you really need. Users and store reviewers care about this Load your extension unpacked in developer mode to test changes quickly Use a bundler like Vite if you want React or TypeScript in your popup Chrome, Edge, and Firefox share most of the WebExtensions API, so one codebase can often cover several browsers Common mistakes: Requesting broad permissions “just in case” Forgetting that service workers in Manifest V3 can shut down, so don’t keep state only in memory Skipping a clear privacy explanation before publishing The best part is that you can solve a real problem you have every day, and publish it for others to use. Have you built a browser extension, or do you have an idea for one? BrowserExtensions #JavaScript #WebDevelopment #Chrome #React

Powered by Readybot.io

**DEV Community** ## Want to build a browser extension? If …

DEV Community

Steganography for Developers: Hiding Data in Plain Sight

Most developers know cryptography. You encrypt a message, and anyone who intercepts it sees gibberish. But gibberish itself is a signal: it tells an observer that something secret is going on. Steganography takes the opposite approach. Instead of making a message unreadable, it makes the message invisible. The word comes from the Greek steganos ("covered") and graphein ("writing"). The goal is that an observer never suspects a hidden message exists at all. In this article we'll look at how it works, build a working image steganography tool in Python, and discuss where it is (and isn't) useful. Steganography vs. Cryptography Cryptography Steganography Hides The content of a message The existence of a message Visible to an observer? Yes, as ciphertext No, looks like a normal file Failure mode Message stays unreadable Message is discovered They are not competitors. The strongest setups combine them: encrypt first, then hide the ciphertext. If the stego layer is ever detected, the attacker still faces encryption. A Short History Steganography is much older than computers. Herodotus describes messages tattooed on a shaved head and covered by regrown hair. Invisible inks made from lemon juice or milk were used for centuries. In WWII, spies used microdots, entire pages photographed down to the size of a period. Digital steganography follows the same principle: find a place where a small change goes unnoticed. The Core Idea: Redundancy Digital media is full of redundancy. A photo contains far more detail than the human eye can perceive, and an audio file contains frequencies we can't hear. Steganography replaces some of this "unimportant" data with secret data. The classic technique is LSB (Least Significant Bit) substitution. Each pixel in an RGB image has three channels, each stored as a byte (0–255). Consider a red value of 200: 200 = 11001000
If we flip the last bit, we get 11001001, which is 201. Nobody can see the difference between red 200 and red 201. So every channel can carry 1 hidden bit, and every pixel carries 3 bits. A 1920×1080 image has about 2 million pixels, which gives roughly 6.2 million bits, or about 777 KB of hidden capacity. That's plenty for text. Building It in Python Let's implement an LSB encoder and decoder with Pillow. pip install pillow
Step 1: Convert text to bits We need to know where the message ends. A simple approach is to prefix the payload with its length (32 bits). def to_bits(data: bytes) -> list[int]:
length = len(data)
header = [(length >> i) & 1 for i in range(31, -1, -1)]
body = [(byte >> i) & 1 for byte in data for i in range(7, -1, -1)]
return header + body

def from_bits(bits: list[int]) -> bytes:
length = 0
for bit in bits[:32]:
length = (length << 1) | bit

payload = bits[32:32 + length * 8]
out = bytearray()
for i in range(0, len(payload), 8):
    byte = 0
    for bit in payload[i:i + 8]:
        byte = (byte << 1) | bit
    out.append(byte)
return bytes(out)

Step 2: Embed the bits from PIL import Image

def embed(cover_path: str, out_path: str, message: str) -> None:
img = Image.open(cover_path).convert("RGB")
pixels = list(img.getdata())

bits = to_bits(message.encode("utf-8"))
capacity = len(pixels) * 3
if len(bits) > capacity:
    raise ValueError(
        f"Message too large: need {len(bits)} bits, have {capacity}"
    )

new_pixels = []
bit_index = 0
for r, g, b in pixels:
    channels = [r, g, b]
    for c in range(3):
        if bit_index < len(bits):
            channels[c] = (channels[c] & ~1) | bits[bit_index]
            bit_index += 1
    new_pixels.append(tuple(channels))

stego = Image.new("RGB", img.size)
stego.putdata(new_pixels)
stego.save(out_path, format="PNG")  # must be lossless!

Note the output format: PNG. This is critical, and we'll come back to it below. Step 3: Extract the bits def extract(stego_path: str) -...

Powered by Readybot.io

**DEV Community** ## Steganography for Developers: Hiding Data in Plain …

DEV Community

Spec tables on product pages: keep them as real tables, and make them work on a phone

Every hardware or electronics product page ends up with a spec table. Thread size, length, material, voltage range, what's in the box. It's the part of the page people scroll straight to when they already know what they want. It's also the part that gets built as a pile of

s, or a two-column grid that falls apart below 400px. A few notes on doing it in a way that holds up. Use a table. It is tabular data. Key/value specs are exactly what is for. You get row and header relationships for free, and screen readers can announce "Material, stainless steel" instead of two unrelated words.
Specifications

Material Stainless steel A2 Thread M8 Length 60 mm


The two details people skip: scope="row" on the label cell, and a . The caption can be visually hidden if the section already has a heading, but having it means the table has a name when someone jumps between tables. A description list ( ) is also a fair choice for a short, simple list of specs. Once you have more than a handful of rows, or anything that compares variants, go with the table. Comparing variants is where it gets harder When one product comes in several sizes, the spec table often turns into a grid: sizes across the top, properties down the side.
Sizes

6 mm 8 mm 10 mm

Drill bit 6 mm8 mm10 mm Screw size 4–5 mm5–6 mm6–8 mm


(The values here are just example data to show the shape.) With both scope="col" and scope="row", a screen reader can announce the cell with both headers. Without them, someone tabbing through hears a list of numbers with no context. Making it fit on a phone There are two honest options. Pick based on the table's shape. Two-column key/value tables: let them wrap. Most of the time the only CSS you need is to stop the label column from being squeezed: .specs { width: 100%; border-collapse: collapse; }
.specs th, .specs td { padding: .5rem .75rem; text-align: start; vertical-align: top; }
.specs th { width: 40%; font-weight: 600; }
.specs tr + tr > * { border-top: 1px solid #e5e7eb; }
Note text-align: start instead of left. If the site also runs in a right-to-left language, it flips on its own. Wide comparison tables: let them scroll horizontally inside a container, and don't fight it.



Sizes ...


.table-scroll { overflow-x: auto; }
.specs--compare th[scope="row"] {
position: sticky;
inset-inline-start: 0;
background: #fff;
}
The tabindex="0" and role="region" with a label let keyboard users focus the scroll area and move it with the arrow keys. The sticky first column keeps the row labels visible while the values scroll. What I'd avoid is the "turn every row into a card with display: block" trick. It looks neat, but changing a table's display can strip its table semantics in some browser and screen reader combinations, and then you've lost the thing that made it a table in the first place. If you go that route, test it with an actual screen reader. Small things that make specs easier to read Units in the value, consistently. "60 mm" in every row, not "60" in one row and "6 cm" in the next. If you show two unit systems, pick one as primary and keep the other in a smaller span. Non-breaking space between number and u...

Powered by Readybot.io

**DEV Community** ## Spec tables on product pages: keep them …

DEV Community

Turning an Old Phone Into an AI Lens: Real-Time Reality-to-Otherworld Rendering

The build in this episode is a hardware one: an old phone becomes a camera that shows the world through an image model instead of through glass. Every frame you point it at comes back restyled. The interesting part is not the phone. It is what MOSS Image has to do to make that loop feel live, and where the illusion breaks. The five workflows # Workflow Role in the loop 01 Colour-depth LoRA Light and colour control on the restyle 02 50-step vs 8-step DMD vs 4-step Turbo Picks the operating point 03 Base vs SFT, same parameters Picks the model variant 04 JSON Layout structured composition Keeps the scene structurally readable 05 SFT 50-step high quality The quality ceiling, used for stills The step-count decision is the whole design Live-style rendering has a latency budget measured in single-digit seconds. That rules out 50 steps immediately. Between 8-step DMD and 4-step Turbo, the trade is: 4-step Turbo — fast enough that pointing the phone feels responsive. Detail is soft; fine structure (text, railings, thin branches) dissolves. 8-step DMD — noticeably richer, but the added latency makes the phone feel like a camera with a delay, not a lens. The episode picks Turbo for live use and switches to 8-step for “pause and capture” moments. That split is the actual engineering answer. Where the illusion breaks Three things break it, in order of severity: Motion. Fast panning produces smeared frames because the model re-imagines each frame independently. There is no temporal coherence between frames. Text. Any signage in view gets re-lettered into nonsense within a second or two. Faces. Strangers in the background become stylised, which reads as uncanny rather than magical. Knowing that list is more useful than any demo reel: it tells you what to point the thing at. What this is actually good for Location scouting with a stylised preview — you see composition and lighting relationships quickly. Live performance visuals where latency is tolerable. Teaching: showing people the difference between “what the model sees” and “what is there” is a better demo than a static image. Files HF: https://huggingface.co/AI-KSK/moss-image-five-workflows ModelScope: https://modelscope.cn/models/Sunjian520/moss-image-five-workflows Bilibili (Chinese original): https://www.bilibili.com/video/BV1rTnN6vE7A/ Notes The hardware build is described in the video; the repository contains only the ComfyUI workflows. Tutorial material, not a product. Independent AI-KSK release; not affiliated with the model authors.

Powered by Readybot.io

**DEV Community** ## Turning an Old Phone Into an AI …

DEV Community

Moving a browser game's controls into the arena

A timing game can have simple rules and still make the player look in too many places. That was the problem I worked through while building SlapLoop, a free cartoon browser game against the CPU. The early layout put the arena in one area and the strategy controls, power meter, and a large action button in another. It was understandable as a web page, but it split the player's attention at the exact moment the game needed it. The useful change was to treat the arena as the input surface and make the character's movement communicate the same timing information as the meter. One place to look, one place to act The current interaction is deliberately small: click the arena for an instant slap, or hold and release to time the swing. A short hint explains both actions inside the game, while a separate controls guide provides the detail. Character selection lives in arena settings. Tactics and the once-per-match skill remain close to the action. This matters because the player is making two different kinds of decisions: a slower choice about approach, and a quick choice about release timing. They need different emphasis even when they share the same screen. Removing the large action button also created a responsibility: the clickable surface had to be discoverable. A canvas that responds to input without a visible hint is not automatically more immersive. The hint is part of the interaction, rather than an instruction paragraph competing with the match. Animation should describe the timing state A moving meter is a precise indicator, but the hand movement gives the action a physical meaning. If they disagree, the player has to decide which one to trust. A useful way to think about the renderer is as a consumer of the same normalized power value used by the game. The following is a conceptual sketch, not a copy of the game's source: function timingView(power) {
const bounded = Math.max(0, Math.min(1, power));
return {
meterPosition: bounded,
windupAngle: -0.4 + bounded * 1.1,
};
}
The exact angles depend on the character art and shoulder placement. The important boundary is that the visual system does not invent another timing signal. The meter and the windup should explain one state together. That still leaves room for personality. Different characters can vary their idle movement, follow-through, and reaction without gaining stronger gameplay attributes. In SlapLoop, all 12 characters share those attributes; the differences are visual and expressive. Feedback needs a useful vocabulary The initial result display relied heavily on percentages. A precise number was easy to calculate, but a string of percentages was not an especially memorable match summary. Timing grades give players a more useful vocabulary for comparing their hits. There is an important distinction, though: a timing grade describes the original input, while effective power and damage can also be affected by tactics or a skill. Changing damage should not silently rewrite the timing feedback into a better grade. The same separation helps with the health bars. Distinct colors identify the player and CPU, and changing colors make low health easier to notice. Numeric health can support that signal without being the only way to read it. Waiting is also a game state A browser tab is easy to leave idle. The current match has a 15-second automatic-slap timer so that a turn does not wait indefinitely for input. When time expires, the game swings at the power available at that moment. This should be visible before it happens. A countdown inside the arena explains the deadline; pause controls provide an explicit way to take a break. The result is more predictable than an unexplained automatic action after a long silence. Input, timing, and pause behavior also need to agree on when an action is accepted. An interesting animation cannot compensate for a release that appears to count twice or lands after the match has already changed state. What I would check in ...

Powered by Readybot.io

**DEV Community** ## Moving a browser game's controls into the …

DEV Community

AWS CloudWatch Alarms and SNS: Get Notified When Something Goes Wrong

In the last two posts I set up several accounts and a way for people to sign in. Now the question every real environment hits: when something goes wrong, who finds out, and how fast? The basic answer on AWS is a CloudWatch alarm that sends a message through Amazon SNS. What each service does Amazon CloudWatch collects metrics, such as CPU use or estimated charges, and can watch them with alarms. CloudWatch alarm compares a metric to a threshold and moves between three states: OK, ALARM and INSUFFICIENT_DATA. Amazon SNS (Simple Notification Service) sends a message to everyone subscribed to a topic, by email, SMS or other targets. The building blocks Term What it is Notes Metric A number measured over time Example: CPUUtilization or EstimatedCharges Alarm A rule on one metric Threshold, period and number of periods SNS topic A channel for messages Alarms publish to it Subscription Who receives the topic An email subscription must be confirmed Alarm action What the alarm does on a state change Often: publish to an SNS topic Why a topic and not a direct email One topic can notify a whole team, and you can add people without touching the alarm. The same topic can be reused by many alarms. Later you can add other targets, such as a chat tool or a Lambda function. Hands-on: a billing alert in your own account Sign in with a user that can open the Billing console, and turn on Receive CloudWatch billing alerts in Billing preferences. Switch the Region to US East (N. Virginia), because billing metrics are only published there. Open SNS, create a Standard topic named billing-alerts, and add an Email subscription with your address. Open the email and choose Confirm subscription. Until you do, nothing is delivered. Open CloudWatch, then Alarms, then Create alarm. Select the metric Billing > Total Estimated Charge and set a threshold such as 5 USD. For the alarm action choose In alarm, send to the billing-alerts topic, and create the alarm. Test the notification path with the CLI: aws cloudwatch set-alarm-state --alarm-name --state-value ALARM --state-reason "test" and check that the email arrives. Common mistakes Forgetting to confirm the email subscription. Creating the billing alarm in a Region other than US East (N. Virginia). Setting the threshold so high that the alarm never fires. Sending alerts to one personal inbox that nobody else watches. Key takeaways An alarm watches a metric, SNS delivers the message. Use a topic so you can add people and targets later. Confirm subscriptions and test the path on purpose. Start with a billing alarm in every new account. Tomorrow I'll look at how to see who did what in your account, with AWS CloudTrail. Part of #120DaysOfAWS.

Powered by Readybot.io

**DEV Community** ## AWS CloudWatch Alarms and SNS: Get Notified …

DEV Community

I Built a 3D Chord Progression Generator That Visualizes Music Theory in Your Browser

TL;DR: Music theory is hard to visualize. The 3D Chord Progression Generator makes chords visible on a 3D keyboard, generates progressions by mood, and shows wave harmonics alongside traditional theory - all in your browser with no install required. Chords are easy to hear and hard to picture. You press three keys on a piano, sound comes out, and your ear knows whether it's happy or tense. But what are those notes doing together? Why does C-E-G sound different from C-E♭-G? And how do you move from one chord to the next without it sounding random? I wanted to see the notes light up on a 3D keyboard, with the wave, the harmonics and the theory beside them. So I built the 3D Chord Progression Generator. It runs in the browser. No install, no account, no downloads. You play a chord, pick a mood and a key to get a progression, then explore scales, modes and the circle of fifths. The sounds are made live in your browser, not from recordings. This article covers what the tool is, how it compares with a plain piano app and a theory book, a walk-through on desktop and phone, how I built it and what it cannot do. I built it, so this is written by the person who made it, and that is also why I list the limits at the end. What the 3D Chord Progression Generator is The 3D Chord Progression Generator is a music theory tool that runs in a web browser. It is designed and built by me, Julian Neagu, a solo founder in London who builds AI tools, apps and websites under VisionVix. I made it for learners, songwriters and anyone curious about how chords work. A 3D piano sits in the middle of the screen. Controls surround it. Every panel reacts to what you play, so the notes you press show up as a wave, as harmonics and as a named chord. The header says it plainly: 3D keyboard, 7 instruments, chords, scales, theory. The keyboard spans 25 keys from C3 to C5 - two full octaves. Seven instruments are available, each with customizable parameters for warmth, brightness, and air noise. The analyzer shows the waveform, spectrum, harmonics, and theory in real time. In short: open VisionVix World, press Open Simulators, and choose Chord Progression Generator. You get a 3D keyboard, seven instruments, an analyzer that shows the wave and harmonics of what you play, progressions for six moods, 14 scales and modes, and a circle of fifths. Piano app vs theory book vs 3D chord tool There are three common ways to learn chords, and they do different jobs. Feature Plain piano app Theory book 3D chord tool You can Play notes Read the rules Play and see the rules react Sound One piano None Seven instruments Chords You find them Listed in tables Named as you play them Progressions You write them Examples on a page Generated by mood and key Where Phone or tablet On a shelf Any browser, laptop or phone The tool does not teach music on its own. It gives you something to press, hear and look at while you read or practice. A theory book tells you that a major chord is built from the root, major third and perfect fifth. The 3D Chord Progression Generator shows you those intervals lighting up on the keyboard, labels the chord as "C Major" and displays the frequency ratios. The tool bridges the gap between reading rules and hearing sound. You press, you see, you hear - all at once. If you want to see more of my projects in action, I share walkthroughs and builds on my YouTube channel, where I break down other tools like this one. A walk-through of the 3D Chord Progression Generator 1. Open the tool Everything starts at the VisionVix landing page. The hero shows the 3D Simulation Platform with a green Open Simulators button under the headline. It runs the tools right in your browser, with nothing to install. Press Open Simulators. You arrive at the Choose Your 3D World Simulator page. At the time of writing it shows nine worlds: seven live, two coming soon. Each card has a green Enter Simulator button. Press it on the Chord Progression Generator card. On a phone, the steps a...

Powered by Readybot.io

**DEV Community** ## I Built a 3D Chord Progression Generator …

DEV Community

Consistency beats talent in coding

When I started, I thought great developers were just born smarter. After years of building with Flutter, React.js, and Node.js, I believe something different: consistency matters more than talent. Coding is a skill, and skills grow with regular practice. One hour a day for a year will take you much further than a 12-hour binge once a month. What consistency looks like: Small daily practice: Even 30-60 minutes counts. Show up on the days you don’t feel like it. Building, not just watching: Try to write some code every day, even a small feature or a bug fix. Tracking progress: Keep a GitHub streak, a notes file, or a simple checklist so you can see how far you’ve come. Learning one thing at a time: Finish one topic before jumping to the next shiny tool. Accepting slow days: Some days you’ll understand little. That’s part of the process, so don’t quit. Why it works: Concepts that confuse you today become obvious in a few weeks. Small wins stack up, and then one day you notice you can build things you couldn’t before. You don’t need to be the smartest in the room. You just need to keep showing up. What’s your daily coding habit? Share it below, it might help someone else stay on track. Coding #Consistency #LearnToCode #Programming #DeveloperJourney

Powered by Readybot.io

**DEV Community** ## Consistency beats talent in coding When I …

DEV Community

RefMod Without LoRA Training: Bundling a Character, a Fight Move, a Voice and a Set Into Loadable Files

The usual way to make a model hold a specific character or perform a specific fight move is to train a LoRA. RefMod does something different: it stores the reference as a loadable modification file that conditions the model at inference time. The practical difference is turnaround. A LoRA takes a training run; a RefMod takes the source material and the extraction pass. What goes into a RefMod Six workflows in this episode, in four categories: # Workflow Reference type 01 Character RefMod Single image or folder batch 02 Action RefMod Single video or folder batch 03 Audio RefMod Single audio clip 04 Martial-arts-hall scene RefMod Two camera angles, batch 05 Multi-reference gen A — Apply Applies a stack of RefMods 06 Multi-reference gen B — TextEncode Encodes the textual half of the conditioning The A/B split in 05 and 06 matters: applying a reference and describing it are two separate stages, and you can change one without rebuilding the other. Where it is actually strong Character: holds identity across shots. Face structure, hair, and the read of the outfit survive camera changes. Action: a fight move transfers as motion, not as a still pose. That is the hard part and the reason this is interesting. Scene: a fixed set with two camera angles means you can cut between coverage without the room changing. Where it is weaker Audio RefMod is the least reliable of the four. Timbre transfers, but the cadence of the source clip leaks into the output — if the reference was recorded quickly, the result sounds rushed regardless of what the text says. The realistic workflow Use RefMod to get 90% there, then fix the remaining 10% with a short LoRA only if you need it. That order saves the training run in most cases. Files HF: https://huggingface.co/AI-KSK/minimax-h3-refmod-workflows ModelScope: https://modelscope.cn/models/Sunjian520/minimax-h3-refmod-workflows Video walkthrough (Chinese): https://youtu.be/H5L5sO7dRu8 Bilibili: https://www.bilibili.com/video/BV1F2nZ6SEA7/ Notes ComfyUI exports; the H3 model weights must exist locally. Tutorial material, not a product. Independent AI-KSK release; not affiliated with the model authors or RunningHub.

Powered by Readybot.io

**DEV Community** ## RefMod Without LoRA Training: Bundling a Character, …