<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Widget on Ted Factory</title><link>https://tedfactory.com/en/tags/widget/</link><description>Recent content in Widget on Ted Factory</description><generator>Hugo</generator><language>en</language><lastBuildDate>Tue, 21 Apr 2026 13:14:49 +0900</lastBuildDate><atom:link href="https://tedfactory.com/en/tags/widget/index.xml" rel="self" type="application/rss+xml"/><item><title>Typing Sky</title><link>https://tedfactory.com/en/widgets/typing-sky/</link><pubDate>Fri, 06 Mar 2026 00:00:00 +0900</pubDate><guid>https://tedfactory.com/en/widgets/typing-sky/</guid><description>&lt;h1 id="typing-sky"&gt;Typing Sky&lt;a class="anchor" href="#typing-sky"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;A typing game where you shoot down words flying across the sky. Words from the famous poems and novels listed below scroll from right to left. Type them correctly before they reach the left edge to score points. Each word&amp;rsquo;s character count is added to your score, and the speed increases as you succeed.&lt;/p&gt;

&lt;style&gt;
 .typing-game-wrap {
 position: relative;
 width: 100%;
 max-width: 900px;
 margin: 24px auto;
 font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
 user-select: none;
 }
 .typing-game-wrap *,
 .typing-game-wrap *::before,
 .typing-game-wrap *::after {
 box-sizing: border-box;
 }

 /* HUD */
 .tg-hud {
 display: flex;
 justify-content: space-between;
 align-items: center;
 padding: 8px 16px;
 background: rgba(30, 40, 70, 0.85);
 border-radius: 12px 12px 0 0;
 color: #e8ecf4;
 font-size: 15px;
 gap: 12px;
 flex-wrap: wrap;
 }
 .tg-hud-item { display: flex; align-items: center; gap: 6px; }
 .tg-hud-label { opacity: 0.7; font-size: 13px; }
 .tg-hud-value { font-weight: 700; font-size: 18px; min-width: 32px; text-align: right; }
 #tg-lives-display .tg-heart { color: #ff4d6a; margin-right: 1px; }

 /* Play area */
 .tg-arena {
 position: relative;
 width: 100%;
 height: 340px;
 background: url('/images/widgets/typing-sky-bg.png') center/cover no-repeat;
 overflow: hidden;
 border-left: 4px solid rgba(255, 70, 90, 0.7);
 }
 .tg-lane-line {
 position: absolute;
 left: 0; right: 0;
 height: 1px;
 background: rgba(255,255,255,0.13);
 pointer-events: none;
 }

 /* Words */
 .tg-word {
 position: absolute;
 padding: 4px 14px;
 border-radius: 8px;
 font-size: 18px;
 font-weight: 600;
 letter-spacing: 0.5px;
 white-space: nowrap;
 transition: opacity 0.15s, transform 0.15s;
 text-shadow: 0 1px 3px rgba(0,0,0,0.35);
 pointer-events: none;
 }
 .tg-word.matched {
 opacity: 0;
 transform: scale(1.5);
 }
 .tg-word.highlight {
 outline: 2px solid #ffe066;
 outline-offset: 2px;
 }

 /* Input area */
 .tg-input-bar {
 display: flex;
 gap: 8px;
 padding: 10px 16px;
 background: rgba(30, 40, 70, 0.85);
 border-radius: 0 0 12px 12px;
 }
 #tg-input {
 flex: 1;
 padding: 10px 16px;
 font-size: 20px;
 font-weight: 600;
 border: 2px solid rgba(255,255,255,0.25);
 border-radius: 8px;
 background: rgba(255,255,255,0.12);
 color: #fff;
 outline: none;
 letter-spacing: 1px;
 }
 #tg-input:focus { border-color: rgba(100,180,255,0.7); }
 #tg-input::placeholder { color: rgba(255,255,255,0.35); }
 #tg-input:disabled {
 opacity: 0.4;
 cursor: not-allowed;
 }

 .tg-btn {
 padding: 10px 24px;
 border: none;
 border-radius: 8px;
 font-size: 15px;
 font-weight: 700;
 cursor: pointer;
 transition: background 0.2s, transform 0.1s;
 }
 .tg-btn:active { transform: scale(0.96); }
 .tg-btn-start {
 background: linear-gradient(135deg, #4facfe, #00f2fe);
 color: #fff;
 }
 .tg-btn-start:hover { background: linear-gradient(135deg, #3a9aee, #00d4e0); }

 /* Overlay */
 .tg-overlay {
 position: absolute;
 inset: 0;
 display: flex;
 flex-direction: column;
 align-items: center;
 justify-content: center;
 background: rgba(15, 20, 40, 0.82);
 z-index: 10;
 text-align: center;
 padding: 24px;
 }
 .tg-overlay h2 {
 color: #fff;
 margin: 0 0 8px;
 font-size: 28px;
 }
 .tg-overlay p {
 color: rgba(255,255,255,0.7);
 margin: 4px 0;
 font-size: 15px;
 line-height: 1.6;
 }
 .tg-overlay .tg-final-score {
 font-size: 48px;
 font-weight: 800;
 color: #ffe066;
 margin: 12px 0;
 }
 .tg-overlay .tg-btn {
 margin-top: 18px;
 }

 /* Combo */
 .tg-combo-popup {
 position: absolute;
 top: 50%;
 left: 50%;
 transform: translate(-50%, -50%) scale(0);
 font-size: 32px;
 font-weight: 800;
 color: #ffe066;
 text-shadow: 0 2px 8px rgba(0,0,0,0.5);
 pointer-events: none;
 opacity: 0;
 z-index: 5;
 }
 .tg-combo-popup.show {
 animation: tgComboAnim 0.7s ease-out forwards;
 }
 @keyframes tgComboAnim {
 0% { opacity: 1; transform: translate(-50%, -50%) scale(0.5); }
 40% { opacity: 1; transform: translate(-50%, -50%) scale(1.2); }
 100% { opacity: 0; transform: translate(-50%, -70%) scale(1); }
 }

 /* Score popup */
 .tg-score-popup {
 position: absolute;
 font-size: 22px;
 font-weight: 700;
 color: #7fff7f;
 text-shadow: 0 1px 4px rgba(0,0,0,0.5);
 pointer-events: none;
 opacity: 0;
 z-index: 5;
 }
 .tg-score-popup.show {
 animation: tgScoreAnim 0.6s ease-out forwards;
 }
 @keyframes tgScoreAnim {
 0% { opacity: 1; transform: translateY(0); }
 100% { opacity: 0; transform: translateY(-30px); }
 }
&lt;/style&gt;

&lt;div class="typing-game-wrap" id="typingGame"&gt;
 &lt;!-- HUD --&gt;
 &lt;div class="tg-hud"&gt;
 &lt;div class="tg-hud-item"&gt;
 &lt;span class="tg-hud-label"&gt;SCORE&lt;/span&gt;
 &lt;span class="tg-hud-value" id="tg-score"&gt;0&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="tg-hud-item"&gt;
 &lt;span class="tg-hud-label"&gt;COMBO&lt;/span&gt;
 &lt;span class="tg-hud-value" id="tg-combo"&gt;0&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="tg-hud-item"&gt;
 &lt;span class="tg-hud-label"&gt;SPEED&lt;/span&gt;
 &lt;span class="tg-hud-value" id="tg-speed"&gt;1.0x&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="tg-hud-item" id="tg-lives-display"&gt;
 &lt;span class="tg-hud-label"&gt;LIVES&lt;/span&gt;
 &lt;span class="tg-hud-value" id="tg-lives"&gt;&lt;/span&gt;
 &lt;/div&gt;
 &lt;/div&gt;

 &lt;!-- Arena --&gt;
 &lt;div class="tg-arena" id="tg-arena"&gt;
 &lt;div class="tg-overlay" id="tg-overlay-start"&gt;
 &lt;h2&gt;Typing Sky&lt;/h2&gt;
 &lt;p&gt;Type the words flying across the sky!&lt;/p&gt;</description></item><item><title>3D Tetris Box</title><link>https://tedfactory.com/en/widgets/3d-tetris-box/</link><pubDate>Sat, 07 Mar 2026 00:00:00 +0900</pubDate><guid>https://tedfactory.com/en/widgets/3d-tetris-box/</guid><description>&lt;h1 id="3d-tetris-box"&gt;3D Tetris Box&lt;a class="anchor" href="#3d-tetris-box"&gt;#&lt;/a&gt;&lt;/h1&gt;

&lt;style&gt;
 .tt3-wrap {
 position: relative;
 width: 100%;
 max-width: 1100px;
 margin: 28px auto;
 font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
 color: #10131b;
 }

 .tt3-wrap *,
 .tt3-wrap *::before,
 .tt3-wrap *::after {
 box-sizing: border-box;
 }

 .tt3-hero {
 display: grid;
 grid-template-columns: minmax(0, 1.2fr) minmax(260px, 0.8fr);
 align-items: stretch;
 gap: 12px;
 margin: 0 0 14px;
 padding: 12px;
 border: 1px solid rgba(43, 52, 69, 0.12);
 border-radius: 18px;
 background: linear-gradient(180deg, rgba(255, 255, 255, 0.78), rgba(238, 243, 250, 0.86));
 }

 .tt3-hero-copy {
 display: flex;
 flex-direction: column;
 justify-content: center;
 gap: 10px;
 padding: 8px 6px;
 }

 .tt3-hero-text {
 margin: 0;
 font-size: 14px;
 line-height: 1.65;
 color: #38465e;
 }

 .tt3-hero-text-mobile {
 display: none;
 }

 .tt3-hero-image-wrap {
 border-radius: 12px;
 overflow: hidden;
 border: 1px solid rgba(43, 52, 69, 0.12);
 background: rgba(230, 236, 246, 0.7);
 max-height: 180px;
 }

 .tt3-hero-image {
 display: block;
 width: 100%;
 height: 100%;
 object-fit: cover;
 }

 .tt3-shell {
 background: linear-gradient(180deg, #f5f7fb 0%, #e9edf5 100%);
 border: 1px solid rgba(43, 52, 69, 0.12);
 border-radius: 22px;
 box-shadow:
 0 24px 60px rgba(28, 36, 51, 0.18),
 inset 0 1px 0 rgba(255, 255, 255, 0.8);
 overflow: hidden;
 }

 .tt3-hud {
 display: grid;
 grid-template-columns: repeat(4, minmax(0, 1fr));
 gap: 12px;
 padding: 16px 18px;
 background:
 linear-gradient(180deg, rgba(255, 255, 255, 0.9), rgba(239, 243, 250, 0.92));
 border-bottom: 1px solid rgba(43, 52, 69, 0.1);
 }

 .tt3-card {
 padding: 12px 14px;
 border-radius: 14px;
 background: rgba(255, 255, 255, 0.74);
 border: 1px solid rgba(43, 52, 69, 0.1);
 box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7);
 }

 .tt3-label {
 display: block;
 font-size: 12px;
 letter-spacing: 0.08em;
 color: #697589;
 margin-bottom: 6px;
 }

 .tt3-value {
 font-size: 28px;
 font-weight: 800;
 line-height: 1;
 color: #10131b;
 }

 .tt3-layout {
 display: grid;
 grid-template-columns: minmax(0, 720px) 270px;
 justify-content: center;
 align-items: stretch;
 gap: 18px;
 padding: 18px;
 }

 .tt3-stage {
 position: relative;
 width: 100%;
 align-self: start;
 min-width: 0;
 border-radius: 18px;
 overflow: hidden;
 background: linear-gradient(180deg, #dfe4ee 0%, #cfd7e5 100%);
 border: 1px solid rgba(43, 52, 69, 0.12);
 box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.34);
 }

 .tt3-canvas {
 display: block;
 width: 100%;
 aspect-ratio: 1 / 1;
 cursor: pointer;
 }

 .tt3-overlay {
 position: absolute;
 inset: 0;
 display: flex;
 align-items: center;
 justify-content: center;
 padding: 24px;
 background: rgba(18, 23, 34, 0.34);
 backdrop-filter: blur(3px);
 }

 .tt3-panel {
 width: min(100%, 460px);
 padding: 24px 26px;
 border-radius: 20px;
 background: rgba(252, 253, 255, 0.92);
 border: 1px solid rgba(43, 52, 69, 0.12);
 box-shadow: 0 26px 60px rgba(7, 12, 22, 0.28);
 text-align: center;
 }

 .tt3-panel h2 {
 margin: 0 0 10px;
 font-size: 30px;
 color: #10131b;
 }

 .tt3-panel p {
 margin: 8px 0;
 color: #4a5568;
 line-height: 1.6;
 font-size: 15px;
 }

 .tt3-btn-row {
 display: flex;
 justify-content: center;
 gap: 10px;
 margin-top: 18px;
 flex-wrap: wrap;
 }

 .tt3-btn {
 border: none;
 border-radius: 999px;
 padding: 12px 20px;
 font-size: 14px;
 font-weight: 800;
 cursor: pointer;
 transition: transform 0.12s ease, box-shadow 0.18s ease, background 0.18s ease;
 }

 .tt3-btn:hover {
 transform: translateY(-1px);
 }

 .tt3-btn:active {
 transform: translateY(0);
 }

 .tt3-btn-primary {
 color: #fff;
 background: linear-gradient(135deg, #4f46e5, #06b6d4);
 box-shadow: 0 12px 24px rgba(79, 70, 229, 0.28);
 }

 .tt3-btn-secondary {
 color: #1d2738;
 background: rgba(230, 235, 244, 0.95);
 box-shadow: 0 10px 20px rgba(43, 52, 69, 0.1);
 }

 .tt3-flash {
 position: absolute;
 left: 50%;
 top: 10%;
 transform: translateX(-50%);
 padding: 10px 18px;
 border-radius: 999px;
 background: rgba(16, 19, 27, 0.84);
 color: #fff;
 font-size: 14px;
 font-weight: 800;
 letter-spacing: 0.04em;
 pointer-events: none;
 opacity: 0;
 transition: opacity 0.2s ease, transform 0.2s ease;
 }

 .tt3-flash.show {
 opacity: 1;
 transform: translateX(-50%) translateY(10px);
 }

 .tt3-side {
 align-self: stretch;
 display: grid;
 grid-template-rows: minmax(165px, 0.72fr) minmax(320px, 1.28fr);
 gap: 14px;
 min-height: 0;
 }

 .tt3-side-card {
 display: flex;
 flex-direction: column;
 padding: 16px;
 border-radius: 16px;
 background: rgba(255, 255, 255, 0.8);
 border: 1px solid rgba(43, 52, 69, 0.1);
 min-height: 0;
 }

 .tt3-side-card h3 {
 margin: 0 0 12px;
 font-size: 15px;
 color: #10131b;
 }

 .tt3-preview {
 display: block;
 width: 100%;
 height: 100%;
 flex: 1 1 auto;
 min-height: 140px;
 border-radius: 14px;
 background: linear-gradient(180deg, #eff3f9 0%, #dde4f0 100%);
 border: 1px solid rgba(43, 52, 69, 0.08);
 }

 .tt3-controls {
 display: grid;
 grid-template-columns: repeat(2, minmax(0, 1fr));
 gap: 10px;
 align-content: start;
 }

 .tt3-control-group {
 display: flex;
 flex-direction: column;
 gap: 10px;
 }

 .tt3-key {
 display: flex;
 align-items: center;
 justify-content: space-between;
 gap: 10px;
 padding: 10px 12px;
 border-radius: 12px;
 background: rgba(241, 244, 250, 0.94);
 color: #273244;
 font-size: 13px;
 }

 .tt3-key code {
 min-width: 28px;
 padding: 4px 8px;
 border-radius: 8px;
 background: #10131b;
 color: #fff;
 text-align: center;
 font-weight: 700;
 }

 .tt3-note {
 margin-top: auto;
 padding-top: 12px;
 font-size: 13px;
 color: #586579;
 line-height: 1.6;
 }

 .tt3-note-mobile {
 display: none;
 }

 .tt3-mobile-controls {
 display: none;
 }

 .tt3-mobile-column {
 display: flex;
 flex-direction: column;
 gap: 10px;
 }

 .tt3-mobile-rotate {
 display: grid;
 grid-template-columns: 1fr;
 gap: 10px;
 }

 .tt3-mobile-move {
 display: grid;
 grid-template-columns: repeat(3, minmax(0, 1fr));
 gap: 10px;
 align-items: center;
 }

 .tt3-mobile-spacer {
 min-height: 44px;
 }

 .tt3-mobile-btn {
 display: flex;
 align-items: center;
 justify-content: center;
 min-height: 52px;
 border: none;
 border-radius: 14px;
 background: linear-gradient(180deg, #f4f7fb 0%, #e8edf6 100%);
 color: #111827;
 font-size: 20px;
 font-weight: 800;
 box-shadow:
 inset 0 1px 0 rgba(255, 255, 255, 0.85),
 0 8px 18px rgba(43, 52, 69, 0.08);
 cursor: pointer;
 touch-action: manipulation;
 }

 .tt3-mobile-btn:active {
 transform: translateY(1px) scale(0.98);
 }

 .tt3-mobile-btn-rotate {
 font-size: 18px;
 letter-spacing: 0.04em;
 }

 .tt3-next-card {
 gap: 12px;
 }

 .tt3-next-title-mobile {
 display: none;
 }

 .tt3-footer {
 padding: 0 18px 18px;
 color: #586579;
 font-size: 14px;
 line-height: 1.7;
 }

 .tt3-footer-desktop {
 display: none;
 }

 .tt3-footer-mobile {
 display: none;
 }

 .tt3-footer p {
 margin: 0;
 }

 .tt3-footer p + p {
 margin-top: 10px;
 }

 @media (max-width: 980px) {
 .tt3-hud {
 grid-template-columns: repeat(3, minmax(0, 1fr));
 }

 .tt3-layout {
 grid-template-columns: 1fr;
 }

 .tt3-side {
 grid-template-rows: auto auto;
 }
 }

 @media (max-width: 720px) {
 .tt3-hero {
 grid-template-columns: 1fr;
 margin-bottom: 10px;
 padding: 10px;
 gap: 10px;
 }

 .tt3-hero-text-desktop {
 display: none;
 }

 .tt3-hero-text-mobile {
 display: block;
 }

 .tt3-hero-image-wrap {
 max-height: 120px;
 }

 .tt3-hud {
 grid-template-columns: repeat(2, minmax(0, 1fr));
 }

 .tt3-canvas {
 aspect-ratio: 5 / 4;
 }

 .tt3-layout,
 .tt3-hud,
 .tt3-footer {
 padding-left: 14px;
 padding-right: 14px;
 }

 .tt3-layout {
 padding-top: 14px;
 padding-bottom: 14px;
 }

 .tt3-panel {
 padding: 20px 18px;
 }

 .tt3-footer-desktop {
 display: none;
 }

 .tt3-footer-mobile {
 display: block;
 }

 .tt3-side {
 gap: 12px;
 }

 .tt3-preview {
 height: 98px;
 min-height: 98px;
 flex: none;
 }

 .tt3-next-card {
 flex-direction: row;
 align-items: stretch;
 gap: 12px;
 }

 .tt3-next-card h3 {
 flex: 0 0 84px;
 margin: 0;
 display: flex;
 align-items: center;
 font-size: 17px;
 font-weight: 800;
 line-height: 1.05;
 }

 .tt3-next-title-desktop {
 display: none;
 }

 .tt3-next-title-mobile {
 display: inline;
 }

 .tt3-next-card .tt3-preview {
 width: auto;
 flex: 1 1 auto;
 }

 .tt3-control-card h3,
 .tt3-control-card .tt3-controls,
 .tt3-control-card .tt3-note-desktop {
 display: none;
 }

 .tt3-control-card {
 padding: 14px;
 }

 .tt3-mobile-controls {
 display: grid;
 grid-template-columns: minmax(0, 1fr) minmax(0, 1.45fr);
 gap: 12px;
 align-items: stretch;
 }

 .tt3-note-mobile {
 display: block;
 margin-top: 12px;
 padding-top: 0;
 }
 }
&lt;/style&gt;

&lt;div class="tt3-wrap" id="tt3-game"&gt;
 &lt;div class="tt3-hero"&gt;
 &lt;div class="tt3-hero-copy"&gt;
 &lt;p class="tt3-hero-text tt3-hero-text-desktop"&gt;A 3D block slowly moves away from you into a &lt;code&gt;6 x 6 x 15&lt;/code&gt; box. On desktop, use &lt;code&gt;I / J / K / L&lt;/code&gt; for planar movement, &lt;code&gt;F / D / S&lt;/code&gt; for rotation, and &lt;code&gt;A&lt;/code&gt; for a fast drop.&lt;/p&gt;</description></item><item><title>Seven Poker Simulator</title><link>https://tedfactory.com/en/widgets/seven-poker/</link><pubDate>Mon, 09 Mar 2026 00:00:00 +0900</pubDate><guid>https://tedfactory.com/en/widgets/seven-poker/</guid><description>&lt;h1 id="seven-poker-simulator"&gt;Seven Poker Simulator&lt;a class="anchor" href="#seven-poker-simulator"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Seven Poker (Seven-Card Stud) is a card game where each player receives 7 cards dealt sequentially, and builds the best possible 5-card hand from them. Some cards are dealt face-down and others face-up, making it a game where reading your opponents and strategic betting are key.&lt;/p&gt;
&lt;p&gt;I occasionally get together with close friends for poker nights, and after getting cleaned out one too many times, I decided to build this simulator so I could practice on my own. The 5 AI players each have distinct play styles, so hopefully it helps sharpen your instincts for real games.&lt;/p&gt;</description></item><item><title>Widgets</title><link>https://tedfactory.com/en/widgets/</link><pubDate>Wed, 04 Mar 2026 00:00:00 +0900</pubDate><guid>https://tedfactory.com/en/widgets/</guid><description>&lt;h1 id="widgets"&gt;Widgets&lt;a class="anchor" href="#widgets"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;img src="https://tedfactory.com/images/widgets/widgets-hero.png" alt="Widgets" /&gt;&lt;/p&gt;
&lt;p&gt;This is a home for tools and mini games built with just &lt;strong&gt;HTML&lt;/strong&gt; and &lt;strong&gt;JavaScript&lt;/strong&gt;. Instead of obsessing over polish, I want this to be a lightweight playground where I keep testing the question: “Can the web do &lt;em&gt;this&lt;/em&gt;?”&lt;/p&gt;
&lt;p&gt;All kinds of experimental web apps will show up here. And if something looks surprisingly ordinary, there’s a good chance I built it simply because I actually needed it.&lt;/p&gt;</description></item><item><title>Math Track</title><link>https://tedfactory.com/en/widgets/math-track/</link><pubDate>Tue, 21 Apr 2026 00:00:00 +0900</pubDate><guid>https://tedfactory.com/en/widgets/math-track/</guid><description>&lt;h1 id="math-track"&gt;Math Track&lt;a class="anchor" href="#math-track"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;img src="https://tedfactory.com/images/widgets/math-track-cover.png" alt="Cover image of the Math Track game showing a square board with various operation cells, a red pawn, and a white dice" /&gt;&lt;/p&gt;
&lt;p&gt;A single-player mental-math game where you roll a die and move around a square track of operation cells, keeping a running total in your head. &lt;strong&gt;Only the cell you land on&lt;/strong&gt; applies its operation to the current value. When your pawn returns to the start, type the final value — if it&amp;rsquo;s correct, you advance to the next level. Each level widens the set of operations and the operand range.&lt;/p&gt;</description></item></channel></rss>