@design-ai/cli 4.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +164 -0
- package/AGENTS.ko.md +126 -0
- package/AGENTS.md +182 -0
- package/CHANGELOG.md +6883 -0
- package/CLAUDE.md +39 -0
- package/LICENSE +21 -0
- package/README.ko.md +245 -0
- package/README.md +277 -0
- package/agents/README.md +14 -0
- package/agents/a11y-reviewer.md +121 -0
- package/agents/component-architect.md +57 -0
- package/agents/design-critic.md +46 -0
- package/agents/token-extractor.md +63 -0
- package/cli/bin/design-ai-mcp.mjs +6 -0
- package/cli/bin/design-ai.mjs +40 -0
- package/cli/commands/audit.mjs +111 -0
- package/cli/commands/check.mjs +226 -0
- package/cli/commands/doctor.mjs +141 -0
- package/cli/commands/examples.mjs +58 -0
- package/cli/commands/help.mjs +271 -0
- package/cli/commands/install.mjs +161 -0
- package/cli/commands/learn.mjs +1871 -0
- package/cli/commands/list.mjs +143 -0
- package/cli/commands/mcp.mjs +27 -0
- package/cli/commands/pack.mjs +211 -0
- package/cli/commands/prompt.mjs +199 -0
- package/cli/commands/route.mjs +247 -0
- package/cli/commands/search.mjs +60 -0
- package/cli/commands/show.mjs +52 -0
- package/cli/commands/site.mjs +558 -0
- package/cli/commands/status.mjs +161 -0
- package/cli/commands/uninstall.mjs +119 -0
- package/cli/commands/update.mjs +184 -0
- package/cli/commands/version.mjs +94 -0
- package/cli/commands/workspace.mjs +176 -0
- package/cli/lib/brief.mjs +52 -0
- package/cli/lib/check.mjs +642 -0
- package/cli/lib/dispatch.mjs +109 -0
- package/cli/lib/doctor.mjs +505 -0
- package/cli/lib/examples.mjs +258 -0
- package/cli/lib/exec.mjs +63 -0
- package/cli/lib/help-flags.mjs +5 -0
- package/cli/lib/learn.mjs +3694 -0
- package/cli/lib/log.mjs +47 -0
- package/cli/lib/mcp-server.mjs +426 -0
- package/cli/lib/output.mjs +101 -0
- package/cli/lib/pack.mjs +599 -0
- package/cli/lib/paths.mjs +63 -0
- package/cli/lib/prompt.mjs +603 -0
- package/cli/lib/route.mjs +740 -0
- package/cli/lib/search.mjs +158 -0
- package/cli/lib/show.mjs +161 -0
- package/cli/lib/signals.mjs +2337 -0
- package/cli/lib/site.mjs +6617 -0
- package/cli/lib/skill-proposals.mjs +2046 -0
- package/cli/lib/suggest.mjs +66 -0
- package/cli/lib/workspace.mjs +1056 -0
- package/commands/README.md +25 -0
- package/commands/component-spec.md +34 -0
- package/commands/conversational.md +44 -0
- package/commands/design-from-brief.md +141 -0
- package/commands/design-review.md +62 -0
- package/commands/document-from-brief.md +47 -0
- package/commands/extract-tokens.md +38 -0
- package/commands/game-ui.md +40 -0
- package/commands/illustration.md +37 -0
- package/commands/iterate.md +167 -0
- package/commands/motion-design.md +54 -0
- package/commands/palette-from-brand.md +50 -0
- package/commands/print.md +49 -0
- package/commands/slide-deck.md +46 -0
- package/commands/spatial.md +47 -0
- package/commands/stability-review.md +74 -0
- package/commands/video.md +42 -0
- package/commands/website-improvement.md +77 -0
- package/docs/AGENT-DEVELOPMENT.md +658 -0
- package/docs/AI-LEARNING.md +429 -0
- package/docs/AIDER-INTEGRATION.md +224 -0
- package/docs/ARCHITECTURE.ko.md +183 -0
- package/docs/ARCHITECTURE.md +105 -0
- package/docs/CODEX-INTEGRATION.md +311 -0
- package/docs/COMPANY-WEBSITE-DOGFOOD.ko.md +144 -0
- package/docs/COMPANY-WEBSITE-DOGFOOD.md +150 -0
- package/docs/COMPANY-WEBSITE-INTAKE-TEMPLATE.ko.md +153 -0
- package/docs/COMPANY-WEBSITE-INTAKE-TEMPLATE.md +154 -0
- package/docs/CONTRIBUTING.ko.md +203 -0
- package/docs/CONTRIBUTING.md +242 -0
- package/docs/CURSOR-INTEGRATION.md +220 -0
- package/docs/DISTRIBUTION.ko.md +248 -0
- package/docs/DISTRIBUTION.md +253 -0
- package/docs/DOGFOOD-FINDINGS.md +180 -0
- package/docs/DOGFOOD-V4-FINDINGS.md +139 -0
- package/docs/DOGFOOD-V4-MKDOCS-FINDINGS.md +233 -0
- package/docs/DOGFOOD-V4-NPM-FINDINGS.md +157 -0
- package/docs/DOGFOOD-V4-VSCODE-FINDINGS.md +135 -0
- package/docs/FIGMA-INTEGRATION.md +222 -0
- package/docs/MCP-INTEGRATION.md +243 -0
- package/docs/MIGRATION-v4.md +121 -0
- package/docs/PLUGIN-PACKAGING.md +240 -0
- package/docs/PRODUCT-READINESS.md +66 -0
- package/docs/QUICKSTART.ko.md +178 -0
- package/docs/QUICKSTART.md +179 -0
- package/docs/RELEASE-CHECKLIST.md +292 -0
- package/docs/ROADMAP.md +19495 -0
- package/docs/SESSION-LOG.md +940 -0
- package/docs/TOKEN-SYNC.md +237 -0
- package/docs/USING.ko.md +206 -0
- package/docs/USING.md +218 -0
- package/docs/WEBSITE-IMPROVEMENT.ko.md +75 -0
- package/docs/WEBSITE-IMPROVEMENT.md +89 -0
- package/docs/announcements/README.md +56 -0
- package/docs/announcements/dev-to-korea.md +206 -0
- package/docs/announcements/hashnode-post.ko.md +232 -0
- package/docs/announcements/okky-post.ko.md +158 -0
- package/docs/announcements/press-kit.md +101 -0
- package/docs/announcements/reddit-r-korea.md +196 -0
- package/docs/announcements/show-hn.md +114 -0
- package/docs/announcements/twitter-thread.md +255 -0
- package/docs/external-status.md +34 -0
- package/docs/integrations/aider-walkthrough.ko.md +275 -0
- package/docs/integrations/aider-walkthrough.md +274 -0
- package/docs/integrations/codex-walkthrough.ko.md +297 -0
- package/docs/integrations/codex-walkthrough.md +297 -0
- package/docs/integrations/cursor-walkthrough.ko.md +281 -0
- package/docs/integrations/cursor-walkthrough.md +284 -0
- package/docs/integrations/design-ai-mcp-server.md +169 -0
- package/docs/integrations/figma-mcp.md +149 -0
- package/docs/integrations/github-mcp.md +178 -0
- package/docs/integrations/linear-mcp.md +215 -0
- package/docs/integrations/notion-mcp.md +174 -0
- package/docs/integrations/sdk-walkthrough.ko.md +375 -0
- package/docs/integrations/sdk-walkthrough.md +375 -0
- package/docs/integrations/slack-mcp.md +208 -0
- package/docs/integrations/vscode-walkthrough.ko.md +202 -0
- package/docs/integrations/vscode-walkthrough.md +205 -0
- package/docs/requirements.txt +16 -0
- package/docs/site-overrides/extra.css +83 -0
- package/docs/site-overrides/favicon.svg +4 -0
- package/docs/site-overrides/logo.svg +10 -0
- package/docs/site-overrides/main.html +18 -0
- package/docs/website-console/app.js +2540 -0
- package/docs/website-console/index.html +24 -0
- package/docs/website-console/styles.css +975 -0
- package/examples/README.md +252 -0
- package/examples/cases/dogfood-v4-korean-hr-onboarding.md +356 -0
- package/examples/component-accordion-actions.md +153 -0
- package/examples/component-accordion-details.md +147 -0
- package/examples/component-accordion-summary.md +180 -0
- package/examples/component-accordion.md +229 -0
- package/examples/component-account-card.md +284 -0
- package/examples/component-address-input.md +260 -0
- package/examples/component-affix.md +190 -0
- package/examples/component-alert-dialog.md +210 -0
- package/examples/component-alert-title.md +77 -0
- package/examples/component-alert.md +192 -0
- package/examples/component-amount-input.md +278 -0
- package/examples/component-anchor.md +198 -0
- package/examples/component-app-bar.md +249 -0
- package/examples/component-aspect-ratio.md +156 -0
- package/examples/component-auto-complete.md +199 -0
- package/examples/component-avatar-group.md +170 -0
- package/examples/component-avatar.md +191 -0
- package/examples/component-back-top.md +123 -0
- package/examples/component-backdrop.md +148 -0
- package/examples/component-badge.md +181 -0
- package/examples/component-banner.md +237 -0
- package/examples/component-biometric-gate.md +281 -0
- package/examples/component-blockquote.md +153 -0
- package/examples/component-border-beam.md +207 -0
- package/examples/component-bottom-navigation.md +226 -0
- package/examples/component-box.md +112 -0
- package/examples/component-breadcrumb.md +222 -0
- package/examples/component-button-base.md +190 -0
- package/examples/component-button-group.md +117 -0
- package/examples/component-button.md +213 -0
- package/examples/component-calendar.md +280 -0
- package/examples/component-callout.md +131 -0
- package/examples/component-card-actions.md +101 -0
- package/examples/component-card-content.md +90 -0
- package/examples/component-card-header.md +122 -0
- package/examples/component-card-media.md +79 -0
- package/examples/component-card.md +233 -0
- package/examples/component-carousel.md +266 -0
- package/examples/component-cascader.md +135 -0
- package/examples/component-category-picker.md +271 -0
- package/examples/component-chart.md +237 -0
- package/examples/component-chat-interface.md +399 -0
- package/examples/component-checkbox.md +149 -0
- package/examples/component-click-away-listener.md +87 -0
- package/examples/component-code.md +213 -0
- package/examples/component-collapsible.md +219 -0
- package/examples/component-color-picker.md +110 -0
- package/examples/component-combobox.md +267 -0
- package/examples/component-command.md +299 -0
- package/examples/component-config-provider.md +190 -0
- package/examples/component-context-menu.md +179 -0
- package/examples/component-css-baseline.md +148 -0
- package/examples/component-date-picker.md +249 -0
- package/examples/component-descriptions.md +242 -0
- package/examples/component-dialog-actions.md +111 -0
- package/examples/component-dialog-content-text.md +76 -0
- package/examples/component-dialog-content.md +105 -0
- package/examples/component-dialog-title.md +104 -0
- package/examples/component-dialog.md +176 -0
- package/examples/component-divider.md +182 -0
- package/examples/component-doc-page.md +217 -0
- package/examples/component-drawer.md +257 -0
- package/examples/component-dropdown.md +220 -0
- package/examples/component-email-layout.md +253 -0
- package/examples/component-empty-state.md +269 -0
- package/examples/component-empty.md +172 -0
- package/examples/component-fade.md +87 -0
- package/examples/component-feature-grid.md +201 -0
- package/examples/component-field.md +266 -0
- package/examples/component-filled-input.md +114 -0
- package/examples/component-flex.md +117 -0
- package/examples/component-float-button.md +214 -0
- package/examples/component-form-control-label.md +134 -0
- package/examples/component-form-control.md +113 -0
- package/examples/component-form-controls.md +251 -0
- package/examples/component-form-group.md +86 -0
- package/examples/component-form-helper-text.md +95 -0
- package/examples/component-form-label.md +98 -0
- package/examples/component-form.md +291 -0
- package/examples/component-game-hud.md +362 -0
- package/examples/component-game-menu.md +327 -0
- package/examples/component-grid.md +140 -0
- package/examples/component-grow.md +79 -0
- package/examples/component-hero-block.md +252 -0
- package/examples/component-hover-card.md +211 -0
- package/examples/component-icon-button.md +142 -0
- package/examples/component-icon.md +102 -0
- package/examples/component-illustration.md +280 -0
- package/examples/component-image-list.md +107 -0
- package/examples/component-image.md +282 -0
- package/examples/component-input-adornment.md +101 -0
- package/examples/component-input-base.md +134 -0
- package/examples/component-input-number.md +141 -0
- package/examples/component-input-otp.md +271 -0
- package/examples/component-input.md +213 -0
- package/examples/component-item.md +243 -0
- package/examples/component-kbd.md +197 -0
- package/examples/component-krw-amount.md +219 -0
- package/examples/component-label.md +118 -0
- package/examples/component-layout.md +217 -0
- package/examples/component-link.md +223 -0
- package/examples/component-list-item-avatar.md +72 -0
- package/examples/component-list-item-button.md +139 -0
- package/examples/component-list-item-icon.md +82 -0
- package/examples/component-list-item-text.md +98 -0
- package/examples/component-list-item.md +116 -0
- package/examples/component-list-subheader.md +70 -0
- package/examples/component-list.md +198 -0
- package/examples/component-loading-button.md +125 -0
- package/examples/component-loading-sequence.md +254 -0
- package/examples/component-lottie-player.md +279 -0
- package/examples/component-masonry.md +191 -0
- package/examples/component-mentions.md +189 -0
- package/examples/component-menu-item.md +102 -0
- package/examples/component-menu-list.md +98 -0
- package/examples/component-menu.md +139 -0
- package/examples/component-menubar.md +259 -0
- package/examples/component-message.md +162 -0
- package/examples/component-mobile-stepper.md +155 -0
- package/examples/component-modal.md +220 -0
- package/examples/component-navigation-menu.md +295 -0
- package/examples/component-notification.md +166 -0
- package/examples/component-otp-countdown.md +245 -0
- package/examples/component-outlined-input.md +145 -0
- package/examples/component-page-transition.md +281 -0
- package/examples/component-pagination.md +226 -0
- package/examples/component-paper.md +199 -0
- package/examples/component-pass-auth.md +265 -0
- package/examples/component-payment-brand-button.md +253 -0
- package/examples/component-payment-method-selector.md +272 -0
- package/examples/component-payment-receipt.md +277 -0
- package/examples/component-popconfirm.md +144 -0
- package/examples/component-popover.md +239 -0
- package/examples/component-popper.md +129 -0
- package/examples/component-pricing-cards.md +247 -0
- package/examples/component-progress.md +195 -0
- package/examples/component-qr-code.md +201 -0
- package/examples/component-radio.md +167 -0
- package/examples/component-rate.md +202 -0
- package/examples/component-resizable.md +163 -0
- package/examples/component-result.md +270 -0
- package/examples/component-scroll-area.md +199 -0
- package/examples/component-scroll-reveal.md +320 -0
- package/examples/component-segmented.md +178 -0
- package/examples/component-select.md +258 -0
- package/examples/component-separator.md +177 -0
- package/examples/component-sheet.md +277 -0
- package/examples/component-sidebar.md +257 -0
- package/examples/component-skeleton.md +178 -0
- package/examples/component-slide.md +89 -0
- package/examples/component-slider.md +208 -0
- package/examples/component-snackbar-content.md +92 -0
- package/examples/component-snackbar.md +121 -0
- package/examples/component-sonner.md +165 -0
- package/examples/component-space.md +125 -0
- package/examples/component-spatial-locomotion.md +373 -0
- package/examples/component-spatial-panel.md +330 -0
- package/examples/component-speed-dial-action.md +78 -0
- package/examples/component-speed-dial.md +177 -0
- package/examples/component-spin.md +173 -0
- package/examples/component-spinner.md +204 -0
- package/examples/component-splitter.md +210 -0
- package/examples/component-stack.md +130 -0
- package/examples/component-statistic.md +282 -0
- package/examples/component-step-button.md +157 -0
- package/examples/component-step-connector.md +157 -0
- package/examples/component-step-content.md +121 -0
- package/examples/component-step-icon.md +115 -0
- package/examples/component-step-label.md +101 -0
- package/examples/component-step.md +84 -0
- package/examples/component-steps.md +264 -0
- package/examples/component-stock-chart.md +251 -0
- package/examples/component-swipeable-drawer.md +149 -0
- package/examples/component-switch.md +99 -0
- package/examples/component-tab-scroll-button.md +180 -0
- package/examples/component-tab.md +120 -0
- package/examples/component-table-body.md +82 -0
- package/examples/component-table-cell.md +118 -0
- package/examples/component-table-container.md +75 -0
- package/examples/component-table-footer.md +72 -0
- package/examples/component-table-head.md +78 -0
- package/examples/component-table-pagination.md +137 -0
- package/examples/component-table-row.md +113 -0
- package/examples/component-table-sort-label.md +109 -0
- package/examples/component-table.md +202 -0
- package/examples/component-tabs.md +184 -0
- package/examples/component-tag-badge.md +309 -0
- package/examples/component-tag.md +102 -0
- package/examples/component-testimonial-carousel.md +218 -0
- package/examples/component-textarea-autosize.md +114 -0
- package/examples/component-textarea.md +173 -0
- package/examples/component-time-picker.md +205 -0
- package/examples/component-timeline.md +170 -0
- package/examples/component-toast.md +224 -0
- package/examples/component-toggle-button.md +129 -0
- package/examples/component-toggle.md +220 -0
- package/examples/component-toolbar.md +104 -0
- package/examples/component-tooltip.md +178 -0
- package/examples/component-tour.md +176 -0
- package/examples/component-transaction-list-item.md +243 -0
- package/examples/component-transfer.md +156 -0
- package/examples/component-tree-select.md +202 -0
- package/examples/component-tree.md +297 -0
- package/examples/component-typography.md +215 -0
- package/examples/component-upload.md +295 -0
- package/examples/component-video-hero.md +409 -0
- package/examples/component-video-player.md +340 -0
- package/examples/component-voice-input.md +408 -0
- package/examples/component-watermark.md +217 -0
- package/examples/component-zoom.md +92 -0
- package/examples/doc-explanation-example.md +196 -0
- package/examples/doc-how-to-example.md +205 -0
- package/examples/doc-tutorial-example.md +162 -0
- package/examples/dogfood-korean-fintech-system.md +433 -0
- package/examples/email-transactional-example.md +259 -0
- package/examples/palette-saas-violet.md +235 -0
- package/examples/print-business-card-spec.md +205 -0
- package/examples/print-packaging-spec.md +285 -0
- package/examples/report-example.md +228 -0
- package/examples/slide-deck-example.md +237 -0
- package/examples/website-improvement-report.md +128 -0
- package/examples/website-improvement-workspace.json +126 -0
- package/install.sh +189 -0
- package/knowledge/COVERAGE.md +740 -0
- package/knowledge/PRINCIPLES.md +108 -0
- package/knowledge/a11y/contrast.md +70 -0
- package/knowledge/a11y/keyboard-and-focus.md +108 -0
- package/knowledge/colors/color-theory.md +90 -0
- package/knowledge/colors/mui-palette-structure.md +105 -0
- package/knowledge/colors/palettes-by-product-type.md +876 -0
- package/knowledge/components/INDEX.md +231 -0
- package/knowledge/components/index.json +1470 -0
- package/knowledge/components/shadcn-registry.md +159 -0
- package/knowledge/conversational/ai-chat-interfaces.md +323 -0
- package/knowledge/conversational/chatbot-design.md +312 -0
- package/knowledge/conversational/conversational-ui-fundamentals.md +299 -0
- package/knowledge/conversational/korean-voice-conventions.md +281 -0
- package/knowledge/conversational/voice-ui-patterns.md +297 -0
- package/knowledge/design-tokens/ant-design.md +124 -0
- package/knowledge/design-tokens/material-3.md +235 -0
- package/knowledge/design-tokens/polaris-and-carbon.md +231 -0
- package/knowledge/design-tokens/tailwind-v4.md +284 -0
- package/knowledge/game-ui/game-accessibility.md +317 -0
- package/knowledge/game-ui/game-ui-fundamentals.md +281 -0
- package/knowledge/game-ui/hud-design.md +324 -0
- package/knowledge/game-ui/korean-gaming-conventions.md +312 -0
- package/knowledge/game-ui/menu-systems.md +388 -0
- package/knowledge/i18n/korean-app-store-visual.md +223 -0
- package/knowledge/i18n/korean-document-style.md +301 -0
- package/knowledge/i18n/korean-payments.md +211 -0
- package/knowledge/i18n/korean-product-conventions.md +96 -0
- package/knowledge/i18n/korean-publishing.md +139 -0
- package/knowledge/i18n/korean-typography.md +123 -0
- package/knowledge/icons/curated-sets.md +225 -0
- package/knowledge/illustration/hero-illustrations.md +234 -0
- package/knowledge/illustration/illustration-systems.md +221 -0
- package/knowledge/illustration/mascot-design.md +208 -0
- package/knowledge/illustration/spot-illustrations.md +246 -0
- package/knowledge/illustration/svg-optimization.md +308 -0
- package/knowledge/layout/spacing-and-grid.md +119 -0
- package/knowledge/motion/app-loading-sequences.md +277 -0
- package/knowledge/motion/choreography-depth.md +297 -0
- package/knowledge/motion/marketing-motion.md +223 -0
- package/knowledge/motion/micro-interactions.md +266 -0
- package/knowledge/motion/motion-tools.md +281 -0
- package/knowledge/motion/principles.md +126 -0
- package/knowledge/patterns/auth-flow-design.md +316 -0
- package/knowledge/patterns/b2b-onboarding-flows.md +182 -0
- package/knowledge/patterns/brand-identity.md +238 -0
- package/knowledge/patterns/brand-references.md +97 -0
- package/knowledge/patterns/chart-color-encoding.md +269 -0
- package/knowledge/patterns/chart-types.md +344 -0
- package/knowledge/patterns/dashboard-composition.md +299 -0
- package/knowledge/patterns/design-system-qa.md +356 -0
- package/knowledge/patterns/document-typography.md +248 -0
- package/knowledge/patterns/email-design.md +338 -0
- package/knowledge/patterns/empty-states.md +263 -0
- package/knowledge/patterns/error-states.md +318 -0
- package/knowledge/patterns/form-design.md +237 -0
- package/knowledge/patterns/information-architecture.md +341 -0
- package/knowledge/patterns/landing-hero-design.md +283 -0
- package/knowledge/patterns/landing-page-patterns.md +681 -0
- package/knowledge/patterns/list-and-feed.md +371 -0
- package/knowledge/patterns/mobile-navigation.md +278 -0
- package/knowledge/patterns/money-and-amount.md +301 -0
- package/knowledge/patterns/onboarding.md +300 -0
- package/knowledge/patterns/pricing-page-design.md +261 -0
- package/knowledge/patterns/realtime-data.md +280 -0
- package/knowledge/patterns/report-design.md +330 -0
- package/knowledge/patterns/search-ux.md +373 -0
- package/knowledge/patterns/settings-page.md +325 -0
- package/knowledge/patterns/slide-deck-design.md +316 -0
- package/knowledge/patterns/styles-catalog.md +2599 -0
- package/knowledge/patterns/technical-writing.md +306 -0
- package/knowledge/patterns/ui-reasoning.md +1853 -0
- package/knowledge/patterns/ux-guidelines.md +1454 -0
- package/knowledge/platforms/react-native.md +395 -0
- package/knowledge/print/brochures-and-flyers.md +276 -0
- package/knowledge/print/korean-print-conventions.md +284 -0
- package/knowledge/print/packaging.md +321 -0
- package/knowledge/print/print-fundamentals.md +238 -0
- package/knowledge/print/signage-and-posters.md +235 -0
- package/knowledge/print/stationery.md +262 -0
- package/knowledge/spatial/ar-patterns.md +253 -0
- package/knowledge/spatial/comfort-and-accessibility.md +245 -0
- package/knowledge/spatial/spatial-design-fundamentals.md +346 -0
- package/knowledge/spatial/spatial-ui-elements.md +343 -0
- package/knowledge/spatial/vr-patterns.md +302 -0
- package/knowledge/typography/font-pairings.md +332 -0
- package/knowledge/typography/mui-type-scale.md +57 -0
- package/knowledge/typography/type-scale-fundamentals.md +105 -0
- package/knowledge/video/in-product-video.md +277 -0
- package/knowledge/video/korean-video-conventions.md +247 -0
- package/knowledge/video/marketing-video.md +258 -0
- package/knowledge/video/social-and-short-form.md +257 -0
- package/knowledge/video/video-fundamentals.md +296 -0
- package/package.json +106 -0
- package/skills/README.md +39 -0
- package/skills/color-palette/PLAYBOOK.md +175 -0
- package/skills/color-palette/SKILL.md +6 -0
- package/skills/color-palette/TEMPLATE.md +103 -0
- package/skills/component-spec-writer/PLAYBOOK.md +169 -0
- package/skills/component-spec-writer/SKILL.md +6 -0
- package/skills/component-spec-writer/TEMPLATE.md +115 -0
- package/skills/conversational-ui-designer/PLAYBOOK.md +231 -0
- package/skills/conversational-ui-designer/SKILL.md +6 -0
- package/skills/design-broadcast/PLAYBOOK.md +146 -0
- package/skills/design-broadcast/SKILL.md +6 -0
- package/skills/design-critique/PLAYBOOK.md +137 -0
- package/skills/design-critique/SKILL.md +6 -0
- package/skills/design-pr-review/PLAYBOOK.md +171 -0
- package/skills/design-pr-review/SKILL.md +6 -0
- package/skills/design-system-builder/PLAYBOOK.md +218 -0
- package/skills/design-system-builder/SKILL.md +6 -0
- package/skills/design-system-qa/PLAYBOOK.md +163 -0
- package/skills/design-system-qa/SKILL.md +6 -0
- package/skills/document-author/PLAYBOOK.md +167 -0
- package/skills/document-author/SKILL.md +6 -0
- package/skills/figma-token-sync/PLAYBOOK.md +149 -0
- package/skills/figma-token-sync/SKILL.md +6 -0
- package/skills/game-ui-designer/PLAYBOOK.md +209 -0
- package/skills/game-ui-designer/SKILL.md +6 -0
- package/skills/handoff-spec/PLAYBOOK.md +170 -0
- package/skills/handoff-spec/SKILL.md +6 -0
- package/skills/illustration-designer/PLAYBOOK.md +166 -0
- package/skills/illustration-designer/SKILL.md +6 -0
- package/skills/motion-designer/PLAYBOOK.md +223 -0
- package/skills/motion-designer/SKILL.md +6 -0
- package/skills/print-designer/PLAYBOOK.md +209 -0
- package/skills/print-designer/SKILL.md +6 -0
- package/skills/slide-deck-author/PLAYBOOK.md +198 -0
- package/skills/slide-deck-author/SKILL.md +6 -0
- package/skills/spatial-designer/PLAYBOOK.md +238 -0
- package/skills/spatial-designer/SKILL.md +6 -0
- package/skills/ux-audit/PLAYBOOK.md +142 -0
- package/skills/ux-audit/SKILL.md +6 -0
- package/skills/video-designer/PLAYBOOK.md +240 -0
- package/skills/video-designer/SKILL.md +6 -0
- package/skills/website-improvement/PLAYBOOK.md +118 -0
- package/skills/website-improvement/SKILL.md +6 -0
- package/skills/website-improvement/TEMPLATE.md +103 -0
- package/tools/audit/changelog-generate.py +176 -0
- package/tools/audit/check-coverage.py +483 -0
- package/tools/audit/doctor_assertions.py +256 -0
- package/tools/audit/example-qa.py +108 -0
- package/tools/audit/frontmatter-check.py +199 -0
- package/tools/audit/integration-check.py +95 -0
- package/tools/audit/korean-copy-check.py +161 -0
- package/tools/audit/link-check.py +146 -0
- package/tools/audit/local-ci.py +558 -0
- package/tools/audit/package-contents.py +723 -0
- package/tools/audit/package-smoke.py +22443 -0
- package/tools/audit/raw-hex-check.py +252 -0
- package/tools/audit/registry-smoke.py +8188 -0
- package/tools/audit/release-metadata.py +9832 -0
- package/tools/audit/run-all.py +351 -0
- package/tools/audit/smoke_assertions.py +12742 -0
- package/tools/audit/stability-review.py +332 -0
- package/tools/audit/stale-check.py +156 -0
- package/tools/migrations/add-version-frontmatter.py +132 -0
- package/tools/migrations/bump-last-updated.py +131 -0
- package/tools/migrations/promote-stability.py +172 -0
- package/tools/preview/README.md +58 -0
- package/tools/preview/render-tokens.py +454 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
<!-- hand-written -->
|
|
2
|
+
# `VoiceInput` (custom — push-to-talk + transcript voice input) — spec
|
|
3
|
+
|
|
4
|
+
> Voice input button + listening state UI for chat interfaces, voice search, voice commands. Wraps Web Speech API (or platform STT) with visual feedback, transcript preview, error handling, and Korean voice conventions. Pairs with [`knowledge/conversational/voice-ui-patterns.md`](../knowledge/conversational/voice-ui-patterns.md).
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Voice input in apps requires:
|
|
9
|
+
1. **Visible button** to start / stop listening.
|
|
10
|
+
2. **Listening visual feedback** (waveform, pulse).
|
|
11
|
+
3. **Transcript preview** (real-time as user speaks).
|
|
12
|
+
4. **Error states** (mic permission denied, no speech detected, network).
|
|
13
|
+
5. **Cancel** path (back, slide off).
|
|
14
|
+
6. **Korean STT integration** (Clova, Web Speech, Whisper).
|
|
15
|
+
7. **Reduced-motion respect**.
|
|
16
|
+
8. **Accessibility alt** for non-voice users.
|
|
17
|
+
|
|
18
|
+
`VoiceInput` provides this as a standardized component.
|
|
19
|
+
|
|
20
|
+
## Anatomy
|
|
21
|
+
|
|
22
|
+
### Idle state
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
┌─────┐
|
|
26
|
+
│ 🎤 │ ← mic button (44pt minimum)
|
|
27
|
+
└─────┘
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Listening state (modal or inline)
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
┌──────────────────────────────────┐
|
|
34
|
+
│ ●●●●●●●●●● │ ← waveform / pulse
|
|
35
|
+
│ "배송 언제 와요?" │ ← transcript preview
|
|
36
|
+
│ │
|
|
37
|
+
│ [×] Cancel [✓] Send │
|
|
38
|
+
└──────────────────────────────────┘
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Processing (after stop)
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
┌──────────────────────────────────┐
|
|
45
|
+
│ 처리 중... │ ← spinner
|
|
46
|
+
└──────────────────────────────────┘
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## API
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
<VoiceInput
|
|
53
|
+
onTranscript={(text, isFinal) => handle(text, isFinal)}
|
|
54
|
+
onCancel={handleCancel}
|
|
55
|
+
language="ko-KR"
|
|
56
|
+
variant="modal" // "inline" | "modal" | "button-only"
|
|
57
|
+
maxDuration={30000} // ms; auto-stop
|
|
58
|
+
autoStop // stop on silence
|
|
59
|
+
silenceTimeout={1500} // ms of silence before auto-stop
|
|
60
|
+
showTranscript
|
|
61
|
+
pushToTalk={false} // hold to talk vs tap-to-toggle
|
|
62
|
+
size="md"
|
|
63
|
+
/>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
| Prop | Type | Default | Description |
|
|
67
|
+
| --- | --- | --- | --- |
|
|
68
|
+
| `onTranscript` | `(text: string, isFinal: boolean) => void` | — | Called with interim + final transcript |
|
|
69
|
+
| `onCancel` | `() => void` | — | User cancels |
|
|
70
|
+
| `onError` | `(error) => void` | — | STT or permission errors |
|
|
71
|
+
| `language` | `string` | `"ko-KR"` | BCP-47 language tag |
|
|
72
|
+
| `variant` | `"inline" \| "modal" \| "button-only"` | `"button-only"` | Layout |
|
|
73
|
+
| `maxDuration` | `number` | `30000` | Auto-stop after this many ms |
|
|
74
|
+
| `autoStop` | `boolean` | `true` | Stop on silence |
|
|
75
|
+
| `silenceTimeout` | `number` | `1500` | Ms of silence before auto-stop |
|
|
76
|
+
| `showTranscript` | `boolean` | `true` | Show interim transcript |
|
|
77
|
+
| `pushToTalk` | `boolean` | `false` | Hold (true) vs tap-to-toggle (false) |
|
|
78
|
+
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Button size |
|
|
79
|
+
| `provider` | `"web-speech" \| "clova" \| "whisper" \| "custom"` | `"web-speech"` | STT backend |
|
|
80
|
+
| `disabled` | `boolean` | `false` | Disable button |
|
|
81
|
+
|
|
82
|
+
## Variants
|
|
83
|
+
|
|
84
|
+
### `button-only`
|
|
85
|
+
|
|
86
|
+
Just the mic button. When tapped, opens whatever modal/inline UI is appropriate (configured externally).
|
|
87
|
+
|
|
88
|
+
### `inline`
|
|
89
|
+
|
|
90
|
+
Mic button expands inline to listening UI within parent layout. Used in chat input bars.
|
|
91
|
+
|
|
92
|
+
### `modal`
|
|
93
|
+
|
|
94
|
+
Full-screen / centered modal during listening. Used for voice search, primary voice features.
|
|
95
|
+
|
|
96
|
+
## States
|
|
97
|
+
|
|
98
|
+
| State | Visual | Behavior |
|
|
99
|
+
| --- | --- | --- |
|
|
100
|
+
| `idle` | Mic icon, default | Tap / hold to start |
|
|
101
|
+
| `requesting-permission` | Spinner | Browser permission prompt |
|
|
102
|
+
| `listening` | Animated waveform + transcript | Capturing audio |
|
|
103
|
+
| `processing` | Spinner | STT processing final transcript |
|
|
104
|
+
| `error-permission` | "Mic access required" + Settings link | User denied mic |
|
|
105
|
+
| `error-no-speech` | "Didn't catch that. Try again?" | Silent recording |
|
|
106
|
+
| `error-network` | "Network error. Try again." | STT failed |
|
|
107
|
+
| `disabled` | Grayed out | When `disabled` prop |
|
|
108
|
+
|
|
109
|
+
## Tokens consumed
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
--voice-input-button-bg
|
|
113
|
+
--voice-input-button-fg
|
|
114
|
+
--voice-input-button-bg-active (during listening)
|
|
115
|
+
--voice-input-button-bg-error
|
|
116
|
+
--voice-input-waveform-color (brand color typically)
|
|
117
|
+
--voice-input-waveform-bg
|
|
118
|
+
--voice-input-transcript-fg
|
|
119
|
+
--voice-input-modal-bg (full-screen overlay if modal)
|
|
120
|
+
--motion-fast, --motion-medium
|
|
121
|
+
--ease-out
|
|
122
|
+
--space-md, --space-lg
|
|
123
|
+
--radius-full (mic button is circular)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Visual feedback
|
|
127
|
+
|
|
128
|
+
### Pulse animation (listening)
|
|
129
|
+
|
|
130
|
+
```css
|
|
131
|
+
.voice-input__button[data-state="listening"] {
|
|
132
|
+
animation: pulse 1.5s ease-in-out infinite;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
@keyframes pulse {
|
|
136
|
+
0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 var(--voice-input-button-bg-active); }
|
|
137
|
+
50% { transform: scale(1.05); box-shadow: 0 0 0 8px transparent; }
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
@media (prefers-reduced-motion: reduce) {
|
|
141
|
+
.voice-input__button[data-state="listening"] { animation: none; }
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Waveform
|
|
146
|
+
|
|
147
|
+
Visualize audio level real-time:
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
function Waveform({ analyser }: { analyser: AnalyserNode }) {
|
|
151
|
+
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
152
|
+
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
const canvas = canvasRef.current!;
|
|
155
|
+
const ctx = canvas.getContext("2d")!;
|
|
156
|
+
const bufferLength = analyser.frequencyBinCount;
|
|
157
|
+
const data = new Uint8Array(bufferLength);
|
|
158
|
+
|
|
159
|
+
let rafId: number;
|
|
160
|
+
const draw = () => {
|
|
161
|
+
analyser.getByteFrequencyData(data);
|
|
162
|
+
// ...render bars
|
|
163
|
+
rafId = requestAnimationFrame(draw);
|
|
164
|
+
};
|
|
165
|
+
draw();
|
|
166
|
+
|
|
167
|
+
return () => cancelAnimationFrame(rafId);
|
|
168
|
+
}, [analyser]);
|
|
169
|
+
|
|
170
|
+
return <canvas ref={canvasRef} aria-hidden="true" />;
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
For reduced motion: replace with simple "Listening..." text.
|
|
175
|
+
|
|
176
|
+
## Interaction patterns
|
|
177
|
+
|
|
178
|
+
### Tap-to-toggle (default)
|
|
179
|
+
|
|
180
|
+
1. User taps mic.
|
|
181
|
+
2. Listening starts.
|
|
182
|
+
3. User speaks.
|
|
183
|
+
4. User taps again to stop OR auto-stops on silence.
|
|
184
|
+
5. Transcript sent.
|
|
185
|
+
|
|
186
|
+
### Push-to-talk (PTT)
|
|
187
|
+
|
|
188
|
+
1. User holds mic button.
|
|
189
|
+
2. Listening starts immediately.
|
|
190
|
+
3. User releases when done.
|
|
191
|
+
4. Transcript sent.
|
|
192
|
+
|
|
193
|
+
PTT is preferred for:
|
|
194
|
+
- Walkie-talkie UX.
|
|
195
|
+
- Short utterances.
|
|
196
|
+
- Public spaces (no risk of accidental long recording).
|
|
197
|
+
|
|
198
|
+
Tap-to-toggle preferred for:
|
|
199
|
+
- Long-form input (dictation).
|
|
200
|
+
- Mobile (holding finger is tedious).
|
|
201
|
+
|
|
202
|
+
## Implementation
|
|
203
|
+
|
|
204
|
+
### Web Speech API (browser-native)
|
|
205
|
+
|
|
206
|
+
```tsx
|
|
207
|
+
function VoiceInput({ onTranscript, language = "ko-KR", autoStop = true, silenceTimeout = 1500, ... }: Props) {
|
|
208
|
+
const recognitionRef = useRef<SpeechRecognition>();
|
|
209
|
+
const [state, setState] = useState<"idle" | "listening" | "processing" | "error">("idle");
|
|
210
|
+
const [transcript, setTranscript] = useState("");
|
|
211
|
+
const reduced = usePrefersReducedMotion();
|
|
212
|
+
|
|
213
|
+
const start = async () => {
|
|
214
|
+
try {
|
|
215
|
+
// Permission check (modern API)
|
|
216
|
+
await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
217
|
+
} catch {
|
|
218
|
+
setState("error");
|
|
219
|
+
onError?.({ type: "permission" });
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const SpeechRecognition = window.SpeechRecognition || (window as any).webkitSpeechRecognition;
|
|
224
|
+
if (!SpeechRecognition) {
|
|
225
|
+
onError?.({ type: "unsupported" });
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const recognition = new SpeechRecognition();
|
|
230
|
+
recognition.lang = language;
|
|
231
|
+
recognition.interimResults = true;
|
|
232
|
+
recognition.continuous = autoStop ? false : true;
|
|
233
|
+
|
|
234
|
+
recognition.onresult = (event: SpeechRecognitionEvent) => {
|
|
235
|
+
let interim = "";
|
|
236
|
+
let final = "";
|
|
237
|
+
for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
238
|
+
const result = event.results[i];
|
|
239
|
+
if (result.isFinal) final += result[0].transcript;
|
|
240
|
+
else interim += result[0].transcript;
|
|
241
|
+
}
|
|
242
|
+
const combined = final + interim;
|
|
243
|
+
setTranscript(combined);
|
|
244
|
+
onTranscript(combined, !!final);
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
recognition.onerror = (event: SpeechRecognitionErrorEvent) => {
|
|
248
|
+
setState("error");
|
|
249
|
+
onError?.({ type: event.error });
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
recognition.onend = () => {
|
|
253
|
+
setState("idle");
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
recognition.start();
|
|
257
|
+
recognitionRef.current = recognition;
|
|
258
|
+
setState("listening");
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const stop = () => {
|
|
262
|
+
recognitionRef.current?.stop();
|
|
263
|
+
setState("processing");
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
return (
|
|
267
|
+
<button
|
|
268
|
+
className="voice-input__button"
|
|
269
|
+
data-state={state}
|
|
270
|
+
data-reduced={reduced}
|
|
271
|
+
onClick={state === "idle" ? start : stop}
|
|
272
|
+
aria-label={state === "idle" ? "음성으로 입력" : "녹음 중지"}
|
|
273
|
+
aria-pressed={state === "listening"}
|
|
274
|
+
>
|
|
275
|
+
{state === "idle" && <MicIcon />}
|
|
276
|
+
{state === "listening" && <StopIcon />}
|
|
277
|
+
{state === "processing" && <Spinner />}
|
|
278
|
+
{state === "error" && <ErrorIcon />}
|
|
279
|
+
</button>
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### For Clova / Whisper / custom backend
|
|
285
|
+
|
|
286
|
+
Replace Web Speech with custom STT. Stream microphone audio (MediaRecorder) to backend; receive transcript via WebSocket or chunks.
|
|
287
|
+
|
|
288
|
+
```tsx
|
|
289
|
+
// Pseudocode
|
|
290
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
291
|
+
const recorder = new MediaRecorder(stream);
|
|
292
|
+
recorder.ondataavailable = e => sendChunkToServer(e.data);
|
|
293
|
+
recorder.start(250); // emit every 250ms
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
For Korean: Naver Clova STT API recommended for best Korean recognition; OpenAI Whisper API also strong.
|
|
297
|
+
|
|
298
|
+
## Permission handling
|
|
299
|
+
|
|
300
|
+
First-time user must grant mic permission:
|
|
301
|
+
|
|
302
|
+
```
|
|
303
|
+
┌────────────────────────────────────┐
|
|
304
|
+
│ 음성 입력을 사용하려면 마이크 권한이│
|
|
305
|
+
│ 필요해요. │
|
|
306
|
+
│ │
|
|
307
|
+
│ [권한 요청] │
|
|
308
|
+
└────────────────────────────────────┘
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
If denied:
|
|
312
|
+
```
|
|
313
|
+
┌────────────────────────────────────┐
|
|
314
|
+
│ 마이크 권한이 차단되어 있어요. │
|
|
315
|
+
│ 브라우저 설정에서 권한을 허용해 주세요.│
|
|
316
|
+
│ │
|
|
317
|
+
│ [브라우저 설정 열기] │
|
|
318
|
+
└────────────────────────────────────┘
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## Error handling
|
|
322
|
+
|
|
323
|
+
| Error | UX |
|
|
324
|
+
| --- | --- |
|
|
325
|
+
| Permission denied | Modal with "Enable in settings" |
|
|
326
|
+
| No speech detected | "Didn't catch that. Try again?" with replay option |
|
|
327
|
+
| Network error (cloud STT) | "Connection error. Retry." |
|
|
328
|
+
| Browser unsupported | Hide voice button OR show "Use text input" hint |
|
|
329
|
+
| Timeout (no speech for N seconds) | Auto-stop with "Tap to try again" |
|
|
330
|
+
| STT confidence too low | "Not sure I caught that. Did you mean: [option1] [option2]?" |
|
|
331
|
+
|
|
332
|
+
## Accessibility
|
|
333
|
+
|
|
334
|
+
- **Visual indicator** of listening state (waveform / pulse).
|
|
335
|
+
- **Transcript visible** to deaf users (so they see what's captured).
|
|
336
|
+
- **Text alt input** always available (don't make voice the only path).
|
|
337
|
+
- **ARIA labels**: button has descriptive label.
|
|
338
|
+
- **`aria-live`** for transcript updates.
|
|
339
|
+
- **Reduced motion**: pulse / waveform replaced with static "Listening..." text.
|
|
340
|
+
- **High contrast**: button has visible border, not just color.
|
|
341
|
+
- **Keyboard activation**: Space / Enter triggers start/stop.
|
|
342
|
+
|
|
343
|
+
## Korean conventions
|
|
344
|
+
|
|
345
|
+
| Aspect | Default |
|
|
346
|
+
| --- | --- |
|
|
347
|
+
| Button label | "음성으로 입력" |
|
|
348
|
+
| Listening state | "듣고 있어요..." |
|
|
349
|
+
| Processing | "처리 중..." |
|
|
350
|
+
| No speech | "음성을 인식하지 못했어요. 다시 시도해 주세요." |
|
|
351
|
+
| Permission needed | "마이크 권한이 필요해요" |
|
|
352
|
+
| Cancel button | "취소" |
|
|
353
|
+
| Send button | "전송" |
|
|
354
|
+
|
|
355
|
+
For Korean STT: configure language as `ko-KR`. Web Speech API works for Korean in Chrome / Edge; Naver Clova preferred for production-grade.
|
|
356
|
+
|
|
357
|
+
## Mobile considerations
|
|
358
|
+
|
|
359
|
+
- Touch target minimum 44pt.
|
|
360
|
+
- iOS Safari requires user gesture to start mic.
|
|
361
|
+
- Background tab paused; resume on focus.
|
|
362
|
+
- Battery drain — auto-stop on silence is critical.
|
|
363
|
+
- Bluetooth mic compatibility — test.
|
|
364
|
+
|
|
365
|
+
## Performance
|
|
366
|
+
|
|
367
|
+
- Don't keep mic open when not needed (release stream on stop).
|
|
368
|
+
- For waveform: use `requestAnimationFrame`, not `setInterval`.
|
|
369
|
+
- Stream audio in chunks (don't accumulate full recording in memory).
|
|
370
|
+
- For long-form: chunked upload to STT (250ms chunks typical).
|
|
371
|
+
|
|
372
|
+
## Edge cases
|
|
373
|
+
|
|
374
|
+
- **User taps mic while listening**: stops (toggle behavior).
|
|
375
|
+
- **User leaves page mid-recording**: cleanup; release mic.
|
|
376
|
+
- **Multiple mics on system**: use default; can add device picker.
|
|
377
|
+
- **External mic disconnects**: graceful fallback to internal.
|
|
378
|
+
- **Long pauses mid-utterance**: don't auto-stop too eagerly (user thinking).
|
|
379
|
+
- **STT mishears brand name**: provide post-edit option.
|
|
380
|
+
- **Korean dialect** (Busan, Jeju): test; Whisper handles best.
|
|
381
|
+
- **Code-switching** (Korean + English): STT may misrecognize; large LLMs handle better.
|
|
382
|
+
|
|
383
|
+
## Don't
|
|
384
|
+
|
|
385
|
+
- Don't auto-record without explicit start gesture.
|
|
386
|
+
- Don't keep mic open after stop.
|
|
387
|
+
- Don't omit visual feedback. Listening must be visually obvious.
|
|
388
|
+
- Don't make voice the only input path.
|
|
389
|
+
- Don't ignore reduced-motion users.
|
|
390
|
+
- Don't auto-stop in 200ms if user pauses to think.
|
|
391
|
+
- Don't ship without permission denial UX.
|
|
392
|
+
- Don't ignore Korean STT specifics (language tag, dialect).
|
|
393
|
+
|
|
394
|
+
## References
|
|
395
|
+
|
|
396
|
+
Built on:
|
|
397
|
+
- Web Speech API (`SpeechRecognition` / `webkitSpeechRecognition`)
|
|
398
|
+
- Naver Clova Speech API (Korean cloud STT)
|
|
399
|
+
- OpenAI Whisper API (cloud STT, multilingual)
|
|
400
|
+
- React patterns for permission handling
|
|
401
|
+
|
|
402
|
+
## Cross-reference
|
|
403
|
+
|
|
404
|
+
- [`knowledge/conversational/voice-ui-patterns.md`](../knowledge/conversational/voice-ui-patterns.md) — voice patterns
|
|
405
|
+
- [`knowledge/conversational/conversational-ui-fundamentals.md`](../knowledge/conversational/conversational-ui-fundamentals.md) — fundamentals
|
|
406
|
+
- [`knowledge/conversational/korean-voice-conventions.md`](../knowledge/conversational/korean-voice-conventions.md) — KR
|
|
407
|
+
- [`examples/component-chat-interface.md`](component-chat-interface.md) — chat UI consumer
|
|
408
|
+
- [`knowledge/a11y/keyboard-and-focus.md`](../knowledge/a11y/keyboard-and-focus.md) — keyboard
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# `Watermark` — spec
|
|
2
|
+
|
|
3
|
+
> Citing Ant Design `Watermark`, MUI (no built-in), shadcn-ui (no built-in)
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Adds a repeating watermark overlay (text or image) on top of content. Used for: confidential documents, leaked-photo deterrents in admin/fintech apps, screenshot tracing, "DRAFT" labels.
|
|
8
|
+
|
|
9
|
+
## When Watermark vs alternatives
|
|
10
|
+
|
|
11
|
+
| Pattern | Use |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| **Watermark** | Repeating subtle pattern across the surface |
|
|
14
|
+
| **Banner** | One-time announcement at top |
|
|
15
|
+
| **Toast** | Transient feedback |
|
|
16
|
+
| **Status badge** | Attached to specific elements |
|
|
17
|
+
|
|
18
|
+
Watermarks are subtle by design — the user notices in screenshots, not while using the app.
|
|
19
|
+
|
|
20
|
+
## Anatomy
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
[Page content]
|
|
24
|
+
•︵• •︵•
|
|
25
|
+
[confidential] [confidential]
|
|
26
|
+
•︵• •︵•
|
|
27
|
+
[confidential] [confidential]
|
|
28
|
+
(rotated, semi-transparent)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Watermark is a **layer** over the content, not a component within it.
|
|
32
|
+
|
|
33
|
+
## API
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
<Watermark content="confidential">
|
|
37
|
+
<SensitiveDataPage />
|
|
38
|
+
</Watermark>
|
|
39
|
+
|
|
40
|
+
<Watermark
|
|
41
|
+
content={["민지", "2026.05.07"]} // multi-line
|
|
42
|
+
rotate={-30}
|
|
43
|
+
opacity={0.06}
|
|
44
|
+
spacing={[200, 100]}
|
|
45
|
+
>
|
|
46
|
+
{children}
|
|
47
|
+
</Watermark>
|
|
48
|
+
|
|
49
|
+
<Watermark image="/logo-watermark.svg" imageSize={120}>
|
|
50
|
+
{children}
|
|
51
|
+
</Watermark>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
| Prop | Type | Default | Description |
|
|
55
|
+
| --- | --- | --- | --- |
|
|
56
|
+
| `content` | `string \| string[]` | — | Text watermark (single or multi-line) |
|
|
57
|
+
| `image` | `string` | — | Image watermark (SVG or PNG) |
|
|
58
|
+
| `imageSize` | `number` | — | Image dimension |
|
|
59
|
+
| `rotate` | `number` | `-22` | Degrees |
|
|
60
|
+
| `opacity` | `number` | `0.06` | 0–1 |
|
|
61
|
+
| `color` | `string` | `--color-text-tertiary` | Text color |
|
|
62
|
+
| `fontSize` | `number` | `14` | |
|
|
63
|
+
| `spacing` | `[number, number]` | `[100, 100]` | Horizontal × vertical gap between marks |
|
|
64
|
+
| `zIndex` | `number` | `1` | Above content but below modals |
|
|
65
|
+
| `children` | `ReactNode` | — | Wrapped content |
|
|
66
|
+
|
|
67
|
+
## Implementation strategy
|
|
68
|
+
|
|
69
|
+
Two approaches:
|
|
70
|
+
|
|
71
|
+
### CSS pattern (lightweight)
|
|
72
|
+
|
|
73
|
+
Repeating background image generated as an SVG / canvas and tiled via CSS:
|
|
74
|
+
|
|
75
|
+
```css
|
|
76
|
+
.watermark {
|
|
77
|
+
position: relative;
|
|
78
|
+
}
|
|
79
|
+
.watermark::after {
|
|
80
|
+
content: "";
|
|
81
|
+
position: absolute;
|
|
82
|
+
inset: 0;
|
|
83
|
+
background-image: url("data:image/svg+xml,..."); /* SVG with text */
|
|
84
|
+
background-size: 200px 100px;
|
|
85
|
+
pointer-events: none;
|
|
86
|
+
opacity: 0.06;
|
|
87
|
+
z-index: 1;
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Generate the SVG once with the watermark text + rotation. Embed as data URI for self-contained.
|
|
92
|
+
|
|
93
|
+
### Canvas overlay (more flexible)
|
|
94
|
+
|
|
95
|
+
Render watermark on a canvas overlay:
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
const canvas = document.createElement("canvas");
|
|
99
|
+
canvas.width = window.innerWidth;
|
|
100
|
+
canvas.height = window.innerHeight;
|
|
101
|
+
const ctx = canvas.getContext("2d");
|
|
102
|
+
ctx.globalAlpha = 0.06;
|
|
103
|
+
ctx.font = "14px sans-serif";
|
|
104
|
+
ctx.fillStyle = "currentColor";
|
|
105
|
+
|
|
106
|
+
// Draw repeating rotated text
|
|
107
|
+
for (let x = 0; x < canvas.width; x += 200) {
|
|
108
|
+
for (let y = 0; y < canvas.height; y += 100) {
|
|
109
|
+
ctx.save();
|
|
110
|
+
ctx.translate(x, y);
|
|
111
|
+
ctx.rotate(-22 * Math.PI / 180);
|
|
112
|
+
ctx.fillText("confidential", 0, 0);
|
|
113
|
+
ctx.restore();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Both work. CSS is simpler; canvas is more flexible (can include user-specific watermarks like usernames).
|
|
119
|
+
|
|
120
|
+
## Common use cases
|
|
121
|
+
|
|
122
|
+
### 1. Confidential admin pages
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
<Watermark content="confidential" rotate={-22}>
|
|
126
|
+
<AdminPage />
|
|
127
|
+
</Watermark>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The screenshot taker leaves traces.
|
|
131
|
+
|
|
132
|
+
### 2. Per-user tracing (Korean fintech sensitive screens)
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
<Watermark content={[user.name, user.email, today]}>
|
|
136
|
+
<SensitiveAccountInfo />
|
|
137
|
+
</Watermark>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
If a screenshot leaks, the source user is visible.
|
|
141
|
+
|
|
142
|
+
### 3. "DRAFT" / "PREVIEW" / "SAMPLE"
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
<Watermark content="DRAFT" rotate={-30} opacity={0.08} fontSize={32}>
|
|
146
|
+
<DocumentPreview />
|
|
147
|
+
</Watermark>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Strong indicator that content isn't final.
|
|
151
|
+
|
|
152
|
+
### 4. Brand watermark on shared content
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
<Watermark image="/brand.svg" imageSize={200} opacity={0.1}>
|
|
156
|
+
<ShareableContent />
|
|
157
|
+
</Watermark>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Marketing content that gets exported / screenshotted.
|
|
161
|
+
|
|
162
|
+
## States
|
|
163
|
+
|
|
164
|
+
Watermark doesn't have states. It's purely decorative-with-a-purpose.
|
|
165
|
+
|
|
166
|
+
## Tokens consumed
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
--color-text-tertiary (default text color)
|
|
170
|
+
--color-text-secondary (alternative for higher visibility)
|
|
171
|
+
--space-md
|
|
172
|
+
--font-size-sm
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Opacity is the primary design lever — `0.04–0.10` is the sweet spot. Higher distracts; lower invisible.
|
|
176
|
+
|
|
177
|
+
## Accessibility
|
|
178
|
+
|
|
179
|
+
- Watermarks are **decorative** — `aria-hidden="true"` on the watermark layer.
|
|
180
|
+
- Text content within the watermark is not announced.
|
|
181
|
+
- Watermark must NOT obscure interactive elements (`pointer-events: none` on the layer).
|
|
182
|
+
- For screen readers: watermark is invisible (it's purely a screenshot deterrent).
|
|
183
|
+
|
|
184
|
+
## Performance
|
|
185
|
+
|
|
186
|
+
- For repeated watermarks: render once and tile via CSS (don't render each instance as a DOM element).
|
|
187
|
+
- For canvas: re-render on resize, throttled.
|
|
188
|
+
- For per-user watermarks: generate the SVG/canvas once on mount; cache.
|
|
189
|
+
|
|
190
|
+
## Don't
|
|
191
|
+
|
|
192
|
+
- Don't make watermarks dark / high-contrast — defeats the "subtle" purpose.
|
|
193
|
+
- Don't watermark content the user expects to download cleanly (their own data exports).
|
|
194
|
+
- Don't watermark print pages with text that won't print legibly.
|
|
195
|
+
- Don't put watermarks **above** modals / overlays — `z-index: 1` is right; modals are z-index 1000+.
|
|
196
|
+
- Don't use watermarks for legal compliance alone — they deter, don't prevent. Leaks still happen.
|
|
197
|
+
- Don't omit `pointer-events: none` — clicks through must work.
|
|
198
|
+
|
|
199
|
+
## Korean fintech context
|
|
200
|
+
|
|
201
|
+
For sensitive financial screens:
|
|
202
|
+
- Account balance details
|
|
203
|
+
- Transaction history (when shown to support / admin)
|
|
204
|
+
- Customer data in CRM tools
|
|
205
|
+
- Internal admin views
|
|
206
|
+
|
|
207
|
+
Watermark with the **viewer's name + date** discourages internal screenshot-leaks. KakaoBank, Toss, and major Korean banks use this pattern.
|
|
208
|
+
|
|
209
|
+
## References
|
|
210
|
+
|
|
211
|
+
- Ant Design: [`refs/ant-design/components/watermark/`](../refs/ant-design/components/watermark/) — `Watermark`. Modern Ant addition with comprehensive options.
|
|
212
|
+
- MUI / shadcn-ui: no built-in. Compose with CSS or canvas.
|
|
213
|
+
|
|
214
|
+
## Cross-reference
|
|
215
|
+
|
|
216
|
+
- [`knowledge/a11y/contrast.md`](../knowledge/a11y/contrast.md) — watermark text color considerations
|
|
217
|
+
- [`knowledge/i18n/korean-product-conventions.md`](../knowledge/i18n/korean-product-conventions.md) — Korean fintech screenshot-deterrent conventions
|