thursday-agent 0.4.0 → 0.6.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/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +3 -2
- package/.next/build-manifest.json +3 -3
- package/.next/prerender-manifest.json +3 -3
- package/.next/required-server-files.json +8 -1
- package/.next/routes-manifest.json +18 -6
- package/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +13 -13
- package/.next/server/app/_not-found.segments/_full.segment.rsc +13 -13
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +12 -12
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/api/artifact/route.js +10 -6
- package/.next/server/app/api/artifact/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/memory/files/route.js +6 -5
- package/.next/server/app/api/bot/memory/files/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/memory/route.js +8 -8
- package/.next/server/app/api/bot/memory/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/route.js +8 -8
- package/.next/server/app/api/bot/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/thread/[id]/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/bot/thread/[id]/route.js +15 -0
- package/.next/server/app/api/bot/thread/[id]/route.js.nft.json +1 -0
- package/.next/server/app/api/bot/thread/[id]/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/bot/thread/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/bot/thread/route.js +15 -0
- package/.next/server/app/api/bot/thread/route.js.nft.json +1 -0
- package/.next/server/app/api/bot/thread/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/config/route.js +7 -7
- package/.next/server/app/api/config/route.js.nft.json +1 -1
- package/.next/server/app/api/events/route.js +3 -3
- package/.next/server/app/api/events/route.js.nft.json +1 -1
- package/.next/server/app/api/file/[...path]/route.js +5 -5
- package/.next/server/app/api/file/[...path]/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/catalog/route.js +8 -8
- package/.next/server/app/api/llm-model/catalog/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/credits/route.js +8 -8
- package/.next/server/app/api/llm-model/credits/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/route.js +8 -8
- package/.next/server/app/api/llm-model/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/subscription/route.js +8 -8
- package/.next/server/app/api/llm-model/subscription/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/[name]/route.js +6 -6
- package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/oauth/callback/route.js +4 -4
- package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/route.js +6 -6
- package/.next/server/app/api/mcp/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/tools/route.js +6 -6
- package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -1
- package/.next/server/app/api/memory/edit/route.js +13 -13
- package/.next/server/app/api/memory/edit/route.js.nft.json +1 -1
- package/.next/server/app/api/memory/route.js +7 -6
- package/.next/server/app/api/memory/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/[source]/[name]/route.js +6 -6
- package/.next/server/app/api/skills/[source]/[name]/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/route.js +6 -6
- package/.next/server/app/api/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/thursday/call/route.js +10 -11
- package/.next/server/app/api/thursday/call/route.js.nft.json +1 -1
- package/.next/server/app/api/thursday/skills/route.js +10 -11
- package/.next/server/app/api/thursday/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/thursday/tool-call/route.js +15 -15
- package/.next/server/app/api/thursday/tool-call/route.js.nft.json +1 -1
- package/.next/server/app/api/workspace/missing/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/workspace/missing/route/build-manifest.json +12 -0
- package/.next/server/app/api/workspace/missing/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/workspace/missing/route.js +12 -0
- package/.next/server/app/api/workspace/missing/route.js.map +5 -0
- package/.next/server/app/api/workspace/missing/route.js.nft.json +1 -0
- package/.next/server/app/api/workspace/missing/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/workspace/route.js +5 -4
- package/.next/server/app/api/workspace/route.js.nft.json +1 -1
- package/.next/server/app/artifact/[...path]/page/server-reference-manifest.json +1 -1
- package/.next/server/app/artifact/[...path]/page.js +4 -3
- package/.next/server/app/artifact/[...path]/page.js.nft.json +1 -1
- package/.next/server/app/artifact/[...path]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
- package/.next/server/app/page/server-reference-manifest.json +67 -45
- package/.next/server/app/page.js +10 -9
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +3 -2
- package/.next/server/chunks/[root-of-the-server]__02846fb._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__049f521._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__05luceg._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__06--3q3._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__07bnah_._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__08eae20._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__0_ue8oe._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0c9fgca._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__0g-ueei._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__0h_x6q6._.js +5 -0
- package/.next/server/chunks/{[root-of-the-server]__0pa2n68._.js → [root-of-the-server]__0kxrvxf._.js} +2 -2
- package/.next/server/chunks/{[root-of-the-server]__0q0vvt2._.js → [root-of-the-server]__0ov3iir._.js} +2 -2
- package/.next/server/chunks/[root-of-the-server]__0qwtlmx._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__0sm5xvm._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0ye3da2._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0zp35ul._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__144u9d_._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__18-2tsq._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__1e-ci13._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__1e2365e._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__1fix932._.js +8 -0
- package/.next/server/chunks/{[root-of-the-server]__0ce8nf8._.js → [root-of-the-server]__1g3t7vn._.js} +3 -3
- package/.next/server/chunks/[root-of-the-server]__1kp-83u._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__1kv8p3e._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__1orn-5b._.js +2 -3
- package/.next/server/chunks/_02szwk8._.js +5 -0
- package/.next/server/chunks/_05h2cii._.js +1 -1
- package/.next/server/chunks/_06c9kie._.js +216 -0
- package/.next/server/chunks/{_1x6kd1r._.js → _07y2gj-._.js} +1 -1
- package/.next/server/chunks/_0a43a-0._.js +3 -0
- package/.next/server/chunks/_0bujjey._.js +5 -0
- package/.next/server/chunks/_0c9j6rb._.js +1 -1
- package/.next/server/chunks/_0dkd549._.js +3 -0
- package/.next/server/chunks/_0ej1kvv._.js +3 -0
- package/.next/server/chunks/_0f6ts7z._.js +3 -0
- package/.next/server/chunks/_0gm9hyv._.js +55 -0
- package/.next/server/chunks/_0i55en5._.js +25 -0
- package/.next/server/chunks/_0k50n27._.js +18 -0
- package/.next/server/chunks/_0khihjk._.js +3 -3
- package/.next/server/chunks/_0n74zsf._.js +5 -5
- package/.next/server/chunks/_0nvm9ef._.js +3 -0
- package/.next/server/chunks/_0p56fn0._.js +3 -0
- package/.next/server/chunks/_0recufk._.js +1 -1
- package/.next/server/chunks/_0xbkz10._.js +3 -0
- package/.next/server/chunks/_10tkr26._.js +3 -0
- package/.next/server/chunks/{_0ioz3nd._.js → _11u2kp7._.js} +1 -1
- package/.next/server/chunks/_11ujpya._.js +3 -0
- package/.next/server/chunks/_127nx_p._.js +5 -0
- package/.next/server/chunks/_17l5ygt._.js +1 -1
- package/.next/server/chunks/_19uauj6._.js +3 -0
- package/.next/server/chunks/_1_5mnq4._.js +5 -5
- package/.next/server/chunks/_1abl6t9._.js +55 -0
- package/.next/server/chunks/_1d0j961._.js +3 -3
- package/.next/server/chunks/_1dbixxz._.js +3 -0
- package/.next/server/chunks/_1dc_d1q._.js +98 -0
- package/.next/server/chunks/_1drgfx4._.js +5 -5
- package/.next/server/chunks/_1e48czp._.js +3 -3
- package/.next/server/chunks/_1f31u5x._.js +5 -0
- package/.next/server/chunks/_1kg70wc._.js +3 -3
- package/.next/server/chunks/_1klbcft._.js +5 -0
- package/.next/server/chunks/_1krd9rf._.js +4 -1
- package/.next/server/chunks/_1kwmzab._.js +3 -0
- package/.next/server/chunks/{_1pf4qe-._.js → _1oxj9fa._.js} +1 -1
- package/.next/server/chunks/{_1f46eie._.js → _1pcmdbb._.js} +1 -1
- package/.next/server/chunks/_1qgix-j._.js +3 -0
- package/.next/server/chunks/{lib_logger_ts_1exwjut._.js → _1rpchta._.js} +5 -5
- package/.next/server/chunks/_1vsej-s._.js +5 -0
- package/.next/server/chunks/_1yx0p_s._.js +5 -0
- package/.next/server/chunks/{_0rnf-6n._.js → _20fsr_z._.js} +6 -6
- package/.next/server/chunks/_2128hkj._.js +5 -0
- package/.next/server/chunks/_next-internal_server_app_api_bot_thread_[id]_route_actions_1fstjn2.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_bot_thread_route_actions_003ccso.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_workspace_missing_route_actions_1fidi6p.js +3 -0
- package/.next/server/chunks/config_ts_1g4sz5o._.js +1 -1
- package/.next/server/chunks/features_0-cnt0l._.js +4 -0
- package/.next/server/chunks/features_0hdaci0._.js +4 -0
- package/.next/server/chunks/features_1e39j7-._.js +8 -0
- package/.next/server/chunks/features_bot_bot_query_ts_12mgkl2._.js +1 -1
- package/.next/server/chunks/features_memory_1uqvksn._.js +1 -1
- package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0r28-sm._.js → node_modules_consola_dist_chunks_prompt_mjs_0a7-pbw._.js} +1 -1
- package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0v_7drq._.js → node_modules_consola_dist_chunks_prompt_mjs_0gzvgfv._.js} +1 -1
- package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0i7cvml._.js → node_modules_consola_dist_chunks_prompt_mjs_107pxfn._.js} +1 -1
- package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0icqaqw._.js → node_modules_consola_dist_chunks_prompt_mjs_15hbel8._.js} +1 -1
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_18i-23e._.js +3 -0
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1bewgf3._.js +3 -0
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1kipdeo._.js +3 -0
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1nlww1m._.js +3 -0
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1q77nfx._.js +3 -0
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1xqdzx_._.js +3 -0
- package/.next/server/chunks/{node_modules_zod_v4_1801ax7._.js → node_modules_zod_v4_0lkux5-._.js} +2 -2
- package/.next/server/chunks/{node_modules_zod_v4_1cha_bw._.js → node_modules_zod_v4_1jmr9cq._.js} +2 -2
- package/.next/server/chunks/{node_modules_zod_v4_0ubdflj._.js → node_modules_zod_v4_1yrxmek._.js} +2 -2
- package/.next/server/chunks/node_modules_zod_v4_classic_errors_0tp0y-q.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__09q9med._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0bxsfyn._.js +101 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0lyi8i2._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__16jc196._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__172cq4x._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__18dthbp._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__18e68w8._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1fll8dc._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1mzi-ju._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__1nygfik._.js +5 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1sdphb0._.js +8 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1waa3rc._.js +100 -0
- package/.next/server/chunks/ssr/_00rehl_._.js +3 -0
- package/.next/server/chunks/ssr/{_1lz_cq2._.js → _02oc_h5._.js} +76 -89
- package/.next/server/chunks/ssr/_03_928f._.js +3 -0
- package/.next/server/chunks/ssr/_05yghx6._.js +3 -0
- package/.next/server/chunks/ssr/_08c4z-9._.js +3 -0
- package/.next/server/chunks/ssr/_0_qfdlw._.js +4 -0
- package/.next/server/chunks/ssr/_0c9e5w6._.js +9 -0
- package/.next/server/chunks/ssr/{_0s99bgb._.js → _0dh2e1j._.js} +9 -3
- package/.next/server/chunks/ssr/_0dr-ddg._.js +3 -0
- package/.next/server/chunks/ssr/_0eaog6_._.js +3 -0
- package/.next/server/chunks/ssr/_0evkpto._.js +3 -0
- package/.next/server/chunks/ssr/_0g_rlog._.js +3 -0
- package/.next/server/chunks/ssr/_0geg212._.js +3 -0
- package/.next/server/chunks/ssr/{_1gd8q8l._.js → _0hxt2ul._.js} +2 -2
- package/.next/server/chunks/ssr/_0i_6q1w._.js +2 -2
- package/.next/server/chunks/ssr/_0lu1n_x._.js +1 -1
- package/.next/server/chunks/ssr/{_15j2_8f._.js → _0wzaht-._.js} +2 -2
- package/.next/server/chunks/ssr/_0z-g0uy._.js +3 -0
- package/.next/server/chunks/ssr/_123ttsf._.js +3 -0
- package/.next/server/chunks/ssr/_123y-ah._.js +3 -0
- package/.next/server/chunks/ssr/_12w42gi._.js +3 -0
- package/.next/server/chunks/ssr/_161kqav._.js +3 -0
- package/.next/server/chunks/ssr/{_0ap2fzn._.js → _16c6_xm._.js} +2 -2
- package/.next/server/chunks/ssr/_18opah7._.js +3 -0
- package/.next/server/chunks/ssr/_18xqmny._.js +3 -0
- package/.next/server/chunks/ssr/_1_krfph._.js +3 -0
- package/.next/server/chunks/ssr/{_1-_etts._.js → _1anqots._.js} +2 -2
- package/.next/server/chunks/ssr/_1ey7qn-._.js +70 -0
- package/.next/server/chunks/ssr/_1g9vs7q._.js +3 -0
- package/.next/server/chunks/ssr/_1jmz33w._.js +3 -0
- package/.next/server/chunks/ssr/{_0n3toaw._.js → _1k0spz7._.js} +2 -2
- package/.next/server/chunks/ssr/_1rgtxhr._.js +5 -0
- package/.next/server/chunks/ssr/_1slp25y._.js +3 -0
- package/.next/server/chunks/ssr/{_1fojd41._.js → _1x9pskj._.js} +3 -3
- package/.next/server/chunks/ssr/_1y6b5mr._.js +101 -0
- package/.next/server/chunks/ssr/_1ztk7p6._.js +7 -0
- package/.next/server/chunks/ssr/components_ui_tabs_tsx_0ej40b4._.js +3 -0
- package/.next/server/chunks/ssr/features_bot_thread_query_ts_023eklt._.js +4 -0
- package/.next/server/chunks/ssr/features_config_components_config-setting_tsx_0xfwqdg._.js +1 -1
- package/.next/server/chunks/ssr/features_connectors_components_mcp-setting_tsx_0jmbgvp._.js +1 -1
- package/.next/server/chunks/ssr/{_1-teee5._.js → lib_logger_ts_0-olsze._.js} +2 -7
- package/.next/server/chunks/ssr/{node_modules_0cxaxk9._.js → node_modules_00_51_v._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_04jf_m8._.js → node_modules_022sipm._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0g7fzk3._.js → node_modules_0332gw4._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1cx_ql6._.js → node_modules_04vxchl._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1vh5ntv._.js → node_modules_0746rzi._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0yugy6m._.js → node_modules_0d5uzof._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_09q35v_._.js → node_modules_0exkwcm._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_08dhkiq._.js → node_modules_0fr-ml8._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_14q6g4n._.js → node_modules_0mxvg8h._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0arus10._.js → node_modules_0qapgjr._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1eg7m6c._.js → node_modules_0qbfyjh._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1cz2hle._.js → node_modules_0t-9nup._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_17bwo43._.js → node_modules_0tusx4d._.js} +3 -3
- package/.next/server/chunks/ssr/{node_modules_1efrqxi._.js → node_modules_0vsxbzp._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0_-_a--._.js → node_modules_0vv0-fg._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1gdh31p._.js → node_modules_0wsvp00._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1hpopmo._.js → node_modules_1-urho9._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1_pc9kq._.js → node_modules_16pi_dd._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_00etblx._.js → node_modules_1d53yiq._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1aaxuef._.js → node_modules_1g1eihe._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_198nmll._.js → node_modules_1gpednh._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0pvd7q-._.js → node_modules_1gu1pph._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0b__sgl._.js → node_modules_1he1w8_._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1qpjvy5._.js → node_modules_1lnjapm._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0940ns5._.js → node_modules_1lynj9m._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0x3-ply._.js → node_modules_1seuurl._.js} +2 -2
- package/.next/server/chunks/ssr/{node_modules_14om4ar._.js → node_modules_1u6w1pb._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0had7xd._.js → node_modules_1xn6saw._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1b748ic._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_067_exa._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1z4hm5e._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0nrrdaq._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_@vercel_oidc_dist_06mk8id._.js → node_modules_@vercel_oidc_dist_21a5haa._.js} +1 -1
- package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_trash_mjs_0px2gzr._.js +3 -0
- package/.next/server/middleware-build-manifest.js +3 -3
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +68 -46
- package/.next/static/chunks/0dr16v67vj4n7.js +2 -0
- package/.next/static/chunks/0g4b348l0pve7.js +1 -0
- package/.next/static/chunks/0joan-69kbspd.js +1 -0
- package/.next/static/chunks/0vlgzqo9ka90v.js +1 -0
- package/.next/static/chunks/0zrupxgci5gqc.js +1 -0
- package/.next/static/chunks/10k2xvap03z20.css +1 -0
- package/.next/static/chunks/18mkhstgiqcbt.js +1 -0
- package/.next/static/chunks/{15m575979un5f.js → 1i-u2wzub_to1.js} +2 -2
- package/.next/static/chunks/1kp5nfp06nj9h.js +5 -0
- package/.next/static/chunks/1ohslk4568tm3.js +1 -0
- package/.next/static/chunks/1sbmwswc9k2-1.js +1 -0
- package/.next/static/chunks/1t9qms5pwwa3n.js +1 -0
- package/.next/static/chunks/1vj_5bnbxx84e.js +1 -0
- package/.next/static/chunks/1vqezbhjm3goq.js +1 -0
- package/.next/static/chunks/{3akmqm77muj4-.js → 1wlo979mx-y3w.js} +1 -1
- package/.next/static/chunks/26ql4y-43xwhp.js +1 -0
- package/.next/static/chunks/{0fl3gwe4-l6tz.js → 2_pnccjp6j1ca.js} +1 -1
- package/.next/static/chunks/2a51-ywz9b2a3.js +1 -0
- package/.next/static/chunks/2fvdgxih7x7hr.js +1 -0
- package/.next/static/chunks/2jlz8zp4jax_m.js +18 -0
- package/.next/static/chunks/2nvepds1fu2ux.js +1 -0
- package/.next/static/chunks/3addj3i4-izma.js +1 -0
- package/.next/static/chunks/3bfwpww3m3x4u.js +1 -0
- package/.next/static/chunks/3gfh7nxwusbt0.js +1 -0
- package/.next/static/chunks/3gwa44cvz4qoi.js +1 -0
- package/.next/static/chunks/{38gweqdo4jpfj.js → 3izg0a3k87q1-.js} +5 -5
- package/.next/static/chunks/3zk6q3-3f9swq.js +99 -0
- package/.next/static/chunks/3zkg5iup3v4a2.js +12 -0
- package/.next/static/chunks/405m0bqtoihev.js +1 -0
- package/.next/static/chunks/42wcg3wfg_m_p.js +1 -0
- package/README.md +27 -216
- package/app/api/events/app-event.ts +6 -4
- package/app/api/query-key.ts +25 -16
- package/bin/database.mjs +37 -0
- package/bin/thursday.mjs +44 -28
- package/components/ui/custom-icon.tsx +0 -60
- package/components/ui/radio-group.tsx +37 -0
- package/components/ui/shiny-text.tsx +33 -6
- package/database/migrations/{20260910173049_numerous_spirit → 20260916145701_clever_multiple_man}/migration.sql +80 -24
- package/database/migrations/{20260910173049_numerous_spirit → 20260916145701_clever_multiple_man}/snapshot.json +689 -110
- package/database/migrations/20260916160713_thread_cancelled/migration.sql +2 -0
- package/database/migrations/{20260911030320_opposite_jack_power → 20260916160713_thread_cancelled}/snapshot.json +706 -84
- package/docs/how-it-works.md +39 -36
- package/docs/images/keeps-going.png +0 -0
- package/docs/images/two-minds.png +0 -0
- package/docs/live-calls.md +231 -0
- package/docs/thread-rooms.md +71 -0
- package/features/ai/chatgpt.ts +1 -2
- package/features/ai/live.schema.ts +128 -0
- package/features/ai/load-tools.ts +148 -77
- package/features/ai/model.schema.ts +2 -120
- package/features/ai/model.ts +52 -88
- package/features/ai/prompts/bot.prompt.ts +91 -214
- package/features/ai/prompts/live.prompt.ts +265 -0
- package/features/ai/prompts/prompt-helper.ts +91 -32
- package/features/ai/prompts/thursday.prompt.ts +125 -172
- package/features/ai/tools/bot.tool.ts +38 -145
- package/features/ai/tools/call.tool.ts +1 -1
- package/features/ai/tools/connected.ts +5 -3
- package/features/ai/tools/mcp.tool.ts +7 -4
- package/features/ai/tools/memory.tool.ts +35 -31
- package/features/ai/tools/skills.tool.ts +36 -14
- package/features/ai/tools/studio.tool.ts +26 -21
- package/features/ai/tools/tool-name.ts +2 -5
- package/features/ai/tools/workspace.tool.ts +33 -10
- package/features/artifact/artifact.action.ts +2 -2
- package/features/artifact/artifact.query.ts +112 -61
- package/features/artifact/artifact.schema.ts +8 -6
- package/features/artifact/components/artifact-setting.tsx +83 -33
- package/features/bot/bot.action.ts +43 -36
- package/features/bot/bot.memory.ts +137 -20
- package/features/bot/bot.query.ts +28 -11
- package/features/bot/bot.run.ts +299 -636
- package/features/bot/bot.runner.ts +468 -844
- package/features/bot/bot.schema.ts +93 -82
- package/features/bot/bot.seed.ts +141 -64
- package/features/bot/components/bot-mark.tsx +324 -232
- package/features/bot/components/bot-room.tsx +1613 -697
- package/features/bot/components/bot-roster.tsx +8 -13
- package/features/bot/components/bot-setting.tsx +58 -42
- package/features/bot/components/bot-tool.tsx +55 -87
- package/features/bot/components/mark-palette.tsx +35 -32
- package/features/bot/components/path-chips.tsx +33 -3
- package/features/bot/components/thread-badge.tsx +34 -0
- package/features/bot/components/thread-reply.tsx +639 -0
- package/features/bot/components/thread-setting.tsx +674 -0
- package/features/bot/mark.const.ts +79 -31
- package/features/bot/room.query.ts +889 -0
- package/features/bot/room.schema.ts +64 -0
- package/features/bot/seed-bots.ts +2 -1
- package/features/bot/thread.query.ts +971 -0
- package/features/bot/thread.store.ts +587 -0
- package/features/config/components/voice-key.tsx +113 -88
- package/features/config/config.const.ts +5 -9
- package/features/connectors/mcp.schema.ts +0 -2
- package/features/intro/components/intro.tsx +169 -139
- package/features/memory/components/memory-setting.tsx +2 -7
- package/features/memory/memory.schema.ts +14 -23
- package/features/settings/components/setting-ui.tsx +0 -44
- package/features/settings/components/settings.tsx +12 -12
- package/features/settings/settings.alert.ts +3 -3
- package/features/settings/settings.store.ts +1 -1
- package/features/skills/skills.schema.ts +0 -2
- package/features/thursday/components/ascii-field.tsx +24 -44
- package/features/thursday/components/ascii-orb.tsx +359 -358
- package/features/thursday/components/call-log.tsx +46 -44
- package/features/thursday/components/face.tsx +35 -10
- package/features/thursday/components/tab-state.tsx +3 -3
- package/features/thursday/components/thursday-mark.tsx +1 -0
- package/features/thursday/components/thursday-setting.tsx +631 -332
- package/features/thursday/components/thursday.tsx +106 -41
- package/features/thursday/components/voice-picker.tsx +255 -0
- package/features/thursday/thursday.action.ts +94 -68
- package/features/thursday/thursday.query.ts +49 -30
- package/features/thursday/thursday.schema.ts +27 -30
- package/features/thursday/thursday.store.ts +11 -7
- package/features/thursday/tool-call.ts +3 -3
- package/features/thursday/tool-line.ts +5 -3
- package/features/thursday/use-thursday.ts +725 -450
- package/features/workspace/workspace.query.ts +17 -0
- package/features/workspace/workspace.ts +103 -50
- package/lib/live/live.schema.ts +47 -0
- package/lib/live/live.server.ts +155 -0
- package/lib/live/live.session.ts +574 -0
- package/lib/{realtime/realtime.tap.ts → live/live.tap.ts} +41 -12
- package/lib/live/live.transport.ts +152 -0
- package/lib/protocol/use-server-pages.ts +9 -5
- package/lib/utils.ts +21 -20
- package/package.json +2 -2
- package/public/voices/alloy.ogg +0 -0
- package/public/voices/ash.ogg +0 -0
- package/public/voices/ballad.ogg +0 -0
- package/public/voices/beacon.ogg +0 -0
- package/public/voices/bossa.ogg +0 -0
- package/public/voices/cedar.ogg +0 -0
- package/public/voices/cinder.ogg +0 -0
- package/public/voices/coral.ogg +0 -0
- package/public/voices/delta.ogg +0 -0
- package/public/voices/echo.ogg +0 -0
- package/public/voices/gleam.ogg +0 -0
- package/public/voices/marin.ogg +0 -0
- package/public/voices/meridian.ogg +0 -0
- package/public/voices/quartz.ogg +0 -0
- package/public/voices/ripple.ogg +0 -0
- package/public/voices/sage.ogg +0 -0
- package/public/voices/shimmer.ogg +0 -0
- package/public/voices/stone.ogg +0 -0
- package/public/voices/tempo.ogg +0 -0
- package/public/voices/verse.ogg +0 -0
- package/public/voices/vesper.ogg +0 -0
- package/public/voices/willow.ogg +0 -0
- package/scripts/artifact-paths.test.mts +25 -0
- package/scripts/bot-context.test.mts +1408 -0
- package/scripts/live-history.test.mts +115 -0
- package/scripts/live-session.test.mts +948 -0
- package/server.js +1 -1
- package/skills/browser/SKILL.md +17 -6
- package/skills/computer/SKILL.md +1 -1
- package/skills/find-skills/SKILL.md +3 -8
- package/skills/interactive-page/SKILL.md +12 -7
- package/skills/interactive-page/references/diagram.md +89 -0
- package/skills/interactive-page/scripts/archify/LICENSE +22 -0
- package/skills/interactive-page/scripts/archify/README.md +25 -0
- package/skills/interactive-page/scripts/archify/assets/JetBrainsMono-OFL.txt +93 -0
- package/skills/interactive-page/scripts/archify/assets/template.html +14934 -0
- package/skills/interactive-page/scripts/archify/bin/archify.mjs +2126 -0
- package/skills/interactive-page/scripts/archify/bin/open-artifact.mjs +86 -0
- package/skills/interactive-page/scripts/archify/bin/preview.mjs +653 -0
- package/skills/interactive-page/scripts/archify/bin/visual-check.mjs +829 -0
- package/skills/interactive-page/scripts/archify/delta/architecture-delta.mjs +1223 -0
- package/skills/interactive-page/scripts/archify/examples/agent-run.lifecycle.json +60 -0
- package/skills/interactive-page/scripts/archify/examples/agent-tool-call.workflow.json +94 -0
- package/skills/interactive-page/scripts/archify/examples/async-job-roundtrip.sequence.json +61 -0
- package/skills/interactive-page/scripts/archify/examples/cache-miss-request.sequence.json +82 -0
- package/skills/interactive-page/scripts/archify/examples/checkout-platform.base.architecture.json +31 -0
- package/skills/interactive-page/scripts/archify/examples/checkout-platform.head.architecture.json +31 -0
- package/skills/interactive-page/scripts/archify/examples/deployment-release.lifecycle.json +49 -0
- package/skills/interactive-page/scripts/archify/examples/event-stream.dataflow.json +57 -0
- package/skills/interactive-page/scripts/archify/examples/incident-response.workflow.json +64 -0
- package/skills/interactive-page/scripts/archify/examples/product-analytics.dataflow.json +76 -0
- package/skills/interactive-page/scripts/archify/examples/production-deployment.architecture.json +71 -0
- package/skills/interactive-page/scripts/archify/examples/release-delivery.workflow.json +62 -0
- package/skills/interactive-page/scripts/archify/examples/web-app.architecture.json +46 -0
- package/skills/interactive-page/scripts/archify/migrations/workflow-v2.mjs +279 -0
- package/skills/interactive-page/scripts/archify/recipes/scenarios.mjs +284 -0
- package/skills/interactive-page/scripts/archify/references/authoring-contract.md +243 -0
- package/skills/interactive-page/scripts/archify/references/delivery-contract.md +120 -0
- package/skills/interactive-page/scripts/archify/references/viewer-runtime.md +45 -0
- package/skills/interactive-page/scripts/archify/renderers/architecture/grid.mjs +62 -0
- package/skills/interactive-page/scripts/archify/renderers/architecture/render-architecture.mjs +1078 -0
- package/skills/interactive-page/scripts/archify/renderers/dataflow/README.md +104 -0
- package/skills/interactive-page/scripts/archify/renderers/dataflow/render-dataflow.mjs +483 -0
- package/skills/interactive-page/scripts/archify/renderers/lifecycle/README.md +115 -0
- package/skills/interactive-page/scripts/archify/renderers/lifecycle/render-lifecycle.mjs +561 -0
- package/skills/interactive-page/scripts/archify/renderers/sequence/README.md +114 -0
- package/skills/interactive-page/scripts/archify/renderers/sequence/render-sequence.mjs +464 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/brand-marks.mjs +563 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/cli.mjs +218 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/desktop-readability.mjs +26 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/diagnostics.mjs +127 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/engineering-profiles.mjs +157 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/generated-brand-marks.mjs +3 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/generated-validators.mjs +13 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/geometry.mjs +1423 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/i18n.mjs +595 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/layout-report.mjs +40 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/legend.mjs +217 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/output-path.mjs +340 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/repository-evidence.mjs +238 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/repository-location.mjs +58 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/text-fit.mjs +49 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/utils.mjs +232 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/validator.mjs +86 -0
- package/skills/interactive-page/scripts/archify/renderers/workflow/README.md +223 -0
- package/skills/interactive-page/scripts/archify/renderers/workflow/render-workflow.mjs +35 -0
- package/skills/interactive-page/scripts/archify/renderers/workflow/workflow-compiler.mjs +4400 -0
- package/skills/interactive-page/scripts/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
- package/skills/interactive-page/scripts/archify/schemas/README.md +211 -0
- package/skills/interactive-page/scripts/archify/schemas/architecture.schema.json +178 -0
- package/skills/interactive-page/scripts/archify/schemas/common.schema.json +115 -0
- package/skills/interactive-page/scripts/archify/schemas/dataflow.schema.json +243 -0
- package/skills/interactive-page/scripts/archify/schemas/lifecycle.schema.json +266 -0
- package/skills/interactive-page/scripts/archify/schemas/sequence.schema.json +223 -0
- package/skills/interactive-page/scripts/archify/schemas/workflow.schema.json +428 -0
- package/skills/interactive-page/scripts/archify/scripts/check-render-output.mjs +916 -0
- package/skills/interactive-page/scripts/archify/scripts/render-examples.mjs +26 -0
- package/skills/interactive-page/scripts/bundle-artifact.sh +9 -8
- package/skills/skill-creator/SKILL.md +4 -5
- package/.next/server/app/api/bot/task/[id]/route/app-paths-manifest.json +0 -3
- package/.next/server/app/api/bot/task/[id]/route.js +0 -16
- package/.next/server/app/api/bot/task/[id]/route.js.nft.json +0 -1
- package/.next/server/app/api/bot/task/[id]/route_client-reference-manifest.js +0 -3
- package/.next/server/app/api/bot/task/route/app-paths-manifest.json +0 -3
- package/.next/server/app/api/bot/task/route.js +0 -16
- package/.next/server/app/api/bot/task/route.js.nft.json +0 -1
- package/.next/server/app/api/bot/task/route_client-reference-manifest.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__01dkp4a._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__02va5wz._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__02xjoto._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__04q--0f._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__0bl-e63._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0ffbg85._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0jq4ohy._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__0ls6_8y._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__0ncs9uu._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1-ga0kh._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__11n256_._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__12cabg9._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1339jnv._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__18_teo8._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__1_04mcf._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__1anc1p9._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1ccon1w._.js +0 -10
- package/.next/server/chunks/[root-of-the-server]__1fizn31._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1llj3-b._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1p8m3f4._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1wa1k7r._.js +0 -8
- package/.next/server/chunks/_0-73of8._.js +0 -55
- package/.next/server/chunks/_0-fjql4._.js +0 -26
- package/.next/server/chunks/_00xh_q0._.js +0 -25
- package/.next/server/chunks/_03a0897._.js +0 -3
- package/.next/server/chunks/_051qh8u._.js +0 -3
- package/.next/server/chunks/_05sovvj._.js +0 -3
- package/.next/server/chunks/_0fzqt2y._.js +0 -134
- package/.next/server/chunks/_0mecv0f._.js +0 -26
- package/.next/server/chunks/_0mh8j4m._.js +0 -3
- package/.next/server/chunks/_0obojvv._.js +0 -3
- package/.next/server/chunks/_0sb7tlz._.js +0 -3
- package/.next/server/chunks/_0sbynis._.js +0 -3
- package/.next/server/chunks/_0u10wmw._.js +0 -55
- package/.next/server/chunks/_0u4aiy2._.js +0 -3
- package/.next/server/chunks/_0wp4le3._.js +0 -3
- package/.next/server/chunks/_0y5fg-x._.js +0 -3
- package/.next/server/chunks/_1230wbx._.js +0 -10
- package/.next/server/chunks/_12nheja._.js +0 -3
- package/.next/server/chunks/_13510xh._.js +0 -3
- package/.next/server/chunks/_15hq89o._.js +0 -3
- package/.next/server/chunks/_18-1wcc._.js +0 -55
- package/.next/server/chunks/_1_9mjx-._.js +0 -3
- package/.next/server/chunks/_1c78vw5._.js +0 -229
- package/.next/server/chunks/_1h5_8sk._.js +0 -3
- package/.next/server/chunks/_1hdnxb7._.js +0 -3
- package/.next/server/chunks/_1j8k_j5._.js +0 -3
- package/.next/server/chunks/_1nula3v._.js +0 -3
- package/.next/server/chunks/_1php4eq._.js +0 -3
- package/.next/server/chunks/_1yuv4vp._.js +0 -3
- package/.next/server/chunks/_1zjrdag._.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_bot_task_[id]_route_actions_1_k_8u3.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_bot_task_route_actions_0xln6ra.js +0 -3
- package/.next/server/chunks/features_0rpfxbk._.js +0 -3
- package/.next/server/chunks/features_1qf3cei._.js +0 -3
- package/.next/server/chunks/features_bot_0zt92oh._.js +0 -3
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1xoq2rl._.js +0 -3
- package/.next/server/chunks/ssr/[externals]__0dizgek._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__092knlj._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0mz33a7._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0s9dq5u._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0s9l2sv._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0vnmv-s._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0xsog8n._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__10-dz5o._.js +0 -61
- package/.next/server/chunks/ssr/[root-of-the-server]__1gtlw6v._.js +0 -43
- package/.next/server/chunks/ssr/[root-of-the-server]__1ox7hbk._.js +0 -4
- package/.next/server/chunks/ssr/[root-of-the-server]__202p40z._.js +0 -3
- package/.next/server/chunks/ssr/_001_ms1._.js +0 -28
- package/.next/server/chunks/ssr/_01n3o0m._.js +0 -3
- package/.next/server/chunks/ssr/_0fz4mf_._.js +0 -3
- package/.next/server/chunks/ssr/_0gb4gmf._.js +0 -3
- package/.next/server/chunks/ssr/_0h42fze._.js +0 -3
- package/.next/server/chunks/ssr/_0h7zdni._.js +0 -3
- package/.next/server/chunks/ssr/_0ilna52._.js +0 -42
- package/.next/server/chunks/ssr/_0q0zan6._.js +0 -70
- package/.next/server/chunks/ssr/_0zcjrbg._.js +0 -3
- package/.next/server/chunks/ssr/_0zhoc3r._.js +0 -3
- package/.next/server/chunks/ssr/_13fke0x._.js +0 -3
- package/.next/server/chunks/ssr/_18cymkq._.js +0 -3
- package/.next/server/chunks/ssr/_1b2mjwr._.js +0 -3
- package/.next/server/chunks/ssr/_1f-dg-6._.js +0 -3
- package/.next/server/chunks/ssr/_1h0rw11._.js +0 -3
- package/.next/server/chunks/ssr/_1jhd09t._.js +0 -3
- package/.next/server/chunks/ssr/_1nnsk7z._.js +0 -3
- package/.next/server/chunks/ssr/_1ov37if._.js +0 -3
- package/.next/server/chunks/ssr/_1sji22n._.js +0 -3
- package/.next/server/chunks/ssr/_1vi_uo7._.js +0 -3
- package/.next/server/chunks/ssr/_1vyd1ji._.js +0 -3
- package/.next/server/chunks/ssr/_1xx4zlb._.js +0 -3
- package/.next/server/chunks/ssr/components_ui_1y1l7yj._.js +0 -3
- package/.next/server/chunks/ssr/features_bot_1s_-2vj._.js +0 -3
- package/.next/server/chunks/ssr/lib_realtime_12wg_dd._.js +0 -27
- package/.next/server/chunks/ssr/lib_realtime_15h_v1v._.js +0 -27
- package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_0npjf8-._.js +0 -3
- package/.next/static/chunks/00rd4-v8r7axp.js +0 -1
- package/.next/static/chunks/08qe4as2q428z.js +0 -3
- package/.next/static/chunks/0gnqdjn2lvdad.js +0 -2
- package/.next/static/chunks/0hwap1-p0m5sa.js +0 -1
- package/.next/static/chunks/0r5qcctujhxli.js +0 -1
- package/.next/static/chunks/0w52rrrmuj9r9.js +0 -1
- package/.next/static/chunks/0wcprt5ot5she.js +0 -1
- package/.next/static/chunks/10teww7wt-f6h.js +0 -1
- package/.next/static/chunks/17p6tk6k88dq6.js +0 -1
- package/.next/static/chunks/18a96rkhi4_yd.js +0 -1
- package/.next/static/chunks/1dkjg87pxk0n9.js +0 -28
- package/.next/static/chunks/1jd09sxcjddu1.js +0 -1
- package/.next/static/chunks/1w73ece_6bheu.js +0 -18
- package/.next/static/chunks/214ya3n5gxeih.js +0 -1
- package/.next/static/chunks/22_zkas21rpna.js +0 -1
- package/.next/static/chunks/2fh4-3z_q8b_w.js +0 -1
- package/.next/static/chunks/2h0sd2vumhb15.js +0 -1
- package/.next/static/chunks/2t4vhi3m8ahya.js +0 -1
- package/.next/static/chunks/2tigdtz3dpcy8.js +0 -1
- package/.next/static/chunks/2u7xt6mxg44lf.js +0 -1
- package/.next/static/chunks/3786h5vayt80-.js +0 -28
- package/.next/static/chunks/39j0fvpybzabl.js +0 -40
- package/.next/static/chunks/3cq5g494yuke8.css +0 -1
- package/.next/static/chunks/3hibbjnt85-k6.js +0 -1
- package/.next/static/chunks/3woj-xd7ki5_i.js +0 -1
- package/.next/static/chunks/3xk7yqgomx7yq.js +0 -1
- package/.next/static/chunks/3zmcsnuo25zvq.js +0 -1
- package/database/migrations/20260911030320_opposite_jack_power/migration.sql +0 -1
- package/docs/images/task-thread.png +0 -0
- package/features/bot/components/task-badge.tsx +0 -42
- package/features/bot/components/task-reply.tsx +0 -328
- package/features/bot/components/task-setting.tsx +0 -524
- package/features/bot/task.query.ts +0 -976
- package/features/bot/task.store.ts +0 -489
- package/lib/realtime/client-secret.ts +0 -86
- package/lib/realtime/open-session.ts +0 -31
- package/lib/realtime/openai.ts +0 -35
- package/lib/realtime/realtime.audio.ts +0 -196
- package/lib/realtime/realtime.driver.ts +0 -489
- package/lib/realtime/realtime.protocol.ts +0 -393
- package/lib/realtime/realtime.schema.ts +0 -37
- package/lib/realtime/realtime.session.ts +0 -106
- package/lib/realtime/realtime.transport.ts +0 -384
- package/lib/realtime/xai.ts +0 -39
- /package/.next/server/app/api/bot/{task → thread}/[id]/route/build-manifest.json +0 -0
- /package/.next/server/app/api/bot/{task → thread}/[id]/route/server-reference-manifest.json +0 -0
- /package/.next/server/app/api/bot/{task → thread}/[id]/route.js.map +0 -0
- /package/.next/server/app/api/bot/{task → thread}/route/build-manifest.json +0 -0
- /package/.next/server/app/api/bot/{task → thread}/route/server-reference-manifest.json +0 -0
- /package/.next/server/app/api/bot/{task → thread}/route.js.map +0 -0
- /package/.next/static/{kaTO0UHqF1bMnWgCDik2f → 0qzGoKn2wTERVZtblX1tp}/_buildManifest.js +0 -0
- /package/.next/static/{kaTO0UHqF1bMnWgCDik2f → 0qzGoKn2wTERVZtblX1tp}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{kaTO0UHqF1bMnWgCDik2f → 0qzGoKn2wTERVZtblX1tp}/_ssgManifest.js +0 -0
|
@@ -2,10 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useEffect, useRef } from "react";
|
|
4
4
|
import { ASCII_FACE } from "@/config";
|
|
5
|
-
import {
|
|
6
|
-
createVoiceFollower,
|
|
7
|
-
SPECTRUM_BANDS,
|
|
8
|
-
} from "@/lib/realtime/realtime.tap";
|
|
5
|
+
import { createVoiceFollower, SPECTRUM_BANDS } from "@/lib/live/live.tap";
|
|
9
6
|
import {
|
|
10
7
|
ALPHA_TOP,
|
|
11
8
|
CHAR_RATE,
|
|
@@ -22,24 +19,20 @@ import type { AsciiCharset } from "../face.const";
|
|
|
22
19
|
export type AsciiOrbMode =
|
|
23
20
|
| "idle"
|
|
24
21
|
| "connecting"
|
|
22
|
+
/** The user's turn: the resting body, retyping with the microphone */
|
|
23
|
+
| "listening"
|
|
24
|
+
/** Hanging up: the body draws in and goes out, leaving the field empty */
|
|
25
|
+
| "ending"
|
|
25
26
|
| "speaking"
|
|
26
27
|
/** Running a tool; alive without speaking */
|
|
27
28
|
| "working"
|
|
28
29
|
| "error";
|
|
29
30
|
|
|
30
|
-
/** The list lives in face.const so the settings schema can build the enum without importing this component. */
|
|
31
|
-
export type AsciiOrbCharset = AsciiCharset;
|
|
32
|
-
|
|
33
|
-
/** Expressions the orb can wear while speaking. */
|
|
34
|
-
export type AsciiOrbEmotion = "happy" | "sad" | "love";
|
|
35
|
-
|
|
36
31
|
export type AsciiOrbProps = {
|
|
37
32
|
className?: string;
|
|
38
33
|
mode?: AsciiOrbMode;
|
|
39
34
|
/** "emoji" sprinkles emoji in; "emojiOnly" is all emoji */
|
|
40
|
-
charset?:
|
|
41
|
-
/** Expression while speaking; null for none */
|
|
42
|
-
emotion?: AsciiOrbEmotion | null;
|
|
35
|
+
charset?: AsciiCharset;
|
|
43
36
|
/** Glyph size (px) */
|
|
44
37
|
fontSize?: number;
|
|
45
38
|
/** Cell density; above 1 packs tighter */
|
|
@@ -49,6 +42,11 @@ export type AsciiOrbProps = {
|
|
|
49
42
|
* speaking; without it a synthetic waveform keeps the orb alive (previews).
|
|
50
43
|
*/
|
|
51
44
|
getSpectrum?: () => ArrayLike<number>;
|
|
45
|
+
/**
|
|
46
|
+
* Microphone bands, read the same way. While listening they set how fast the
|
|
47
|
+
* glyphs retype; without them listening is the resting body alone.
|
|
48
|
+
*/
|
|
49
|
+
getMicSpectrum?: () => ArrayLike<number>;
|
|
52
50
|
/** Side length (px). Everything scales with it; cell count scales with area. */
|
|
53
51
|
size?: number;
|
|
54
52
|
/**
|
|
@@ -73,90 +71,37 @@ const ERROR_BITMAP = [
|
|
|
73
71
|
"████ █ █ █ █ ██ █ █",
|
|
74
72
|
];
|
|
75
73
|
|
|
76
|
-
/** Expression bitmaps, 21 x 13; the top 7 rows are eyes, the rest mouth. */
|
|
77
|
-
const FACE_COLS = 21;
|
|
78
|
-
const FACE_ROWS = 13;
|
|
79
|
-
const EYE_ROWS = 7;
|
|
80
|
-
const FACES: Record<AsciiOrbEmotion, string[]> = {
|
|
81
|
-
happy: [
|
|
82
|
-
".....................",
|
|
83
|
-
".....................",
|
|
84
|
-
"....███.......███....",
|
|
85
|
-
"...█████.....█████...",
|
|
86
|
-
"...█████.....█████...",
|
|
87
|
-
"....███.......███....",
|
|
88
|
-
".....................",
|
|
89
|
-
".....................",
|
|
90
|
-
"█...................█",
|
|
91
|
-
".██...............██.",
|
|
92
|
-
"...███.........███...",
|
|
93
|
-
"......█████████......",
|
|
94
|
-
".....................",
|
|
95
|
-
],
|
|
96
|
-
sad: [
|
|
97
|
-
".....................",
|
|
98
|
-
".....................",
|
|
99
|
-
"....███.......███....",
|
|
100
|
-
"...█████.....█████...",
|
|
101
|
-
"...█████.....█████...",
|
|
102
|
-
"....███.......███....",
|
|
103
|
-
".....................",
|
|
104
|
-
".....................",
|
|
105
|
-
"......█████████......",
|
|
106
|
-
"...███.........███...",
|
|
107
|
-
".██...............██.",
|
|
108
|
-
"█...................█",
|
|
109
|
-
".....................",
|
|
110
|
-
],
|
|
111
|
-
love: [
|
|
112
|
-
".....................",
|
|
113
|
-
"...██.██.....██.██...",
|
|
114
|
-
"..███████...███████..",
|
|
115
|
-
"..███████...███████..",
|
|
116
|
-
"...█████.....█████...",
|
|
117
|
-
"....███.......███....",
|
|
118
|
-
".....█.........█.....",
|
|
119
|
-
".....................",
|
|
120
|
-
"█...................█",
|
|
121
|
-
".██...............██.",
|
|
122
|
-
"...███.........███...",
|
|
123
|
-
"......█████████......",
|
|
124
|
-
".....................",
|
|
125
|
-
],
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
/** Expression fade out, blank, fade in (seconds) */
|
|
129
|
-
const FACE_OUT = 0.36;
|
|
130
|
-
const FACE_BLANK = 0.14;
|
|
131
|
-
const FACE_IN = 0.95;
|
|
132
|
-
/** Glyph swap rate for face cells (per second), slower than the background */
|
|
133
|
-
const FACE_CHAR_RATE = 0.75;
|
|
134
|
-
|
|
135
74
|
/** Reference size the tuning constants assume; coordinates are normalized to it. */
|
|
136
75
|
const DESIGN = 680;
|
|
137
76
|
/** Radius (reference units) within which cells exist. Must stay under DESIGN/2 or the canvas clips it. */
|
|
138
77
|
const FIELD_R = 328;
|
|
139
78
|
|
|
140
|
-
/**
|
|
141
|
-
|
|
142
|
-
const SPEAK_BASE = 184;
|
|
79
|
+
/** Where the rim sits while the voice is at the bottom of its range: the resting body's radius (IDLE_R), so speaking starts her own size */
|
|
80
|
+
const SPEAK_BASE = 170;
|
|
143
81
|
/** Swell across a phrase at the top of the voice's range */
|
|
144
82
|
const SPEAK_SWELL = 40;
|
|
145
|
-
/** Kick per syllable */
|
|
146
|
-
const SPEAK_KICK =
|
|
83
|
+
/** Kick per syllable. Held down on purpose: a syllable should push the rim, not throw it */
|
|
84
|
+
const SPEAK_KICK = 85;
|
|
147
85
|
/** Rotating lobes, harmonics 2 and up (the first harmonic shifts the whole circle) */
|
|
148
86
|
const SPEAK_LOBES = 4;
|
|
149
87
|
/** Max depth of one lobe */
|
|
150
|
-
const SPEAK_LOBE_R =
|
|
88
|
+
const SPEAK_LOBE_R = 28;
|
|
89
|
+
/**
|
|
90
|
+
* How fast the whole lobe pattern turns (rad/s), and how much a loud phrase adds.
|
|
91
|
+
* The lobes also drift against each other; this is the turn you actually see,
|
|
92
|
+
* since counter-drifting alone reads as shimmer rather than rotation.
|
|
93
|
+
*/
|
|
94
|
+
const SPEAK_SPIN = 1.1;
|
|
95
|
+
const SPEAK_SPIN_VOICE = 0.9;
|
|
151
96
|
/**
|
|
152
97
|
* Rim range. Past SPEAK_KNEE the rim slows into SPEAK_MAX rather than stopping
|
|
153
98
|
* at it, so a loud syllable still reads as a push instead of a flat edge. Max
|
|
154
99
|
* stays inside FIELD_R or thrown crumbs die at the edge; min keeps a deep
|
|
155
100
|
* breath from collapsing to a dot.
|
|
156
101
|
*/
|
|
157
|
-
const SPEAK_MIN =
|
|
158
|
-
const SPEAK_KNEE =
|
|
159
|
-
const SPEAK_MAX =
|
|
102
|
+
const SPEAK_MIN = 110;
|
|
103
|
+
const SPEAK_KNEE = 205;
|
|
104
|
+
const SPEAK_MAX = 235;
|
|
160
105
|
/** How far a rim cell sits in or out of the rim: the edge is crumbly, not drawn with a compass */
|
|
161
106
|
const SPEAK_ROUGH = 20;
|
|
162
107
|
/** Share of cells a syllable throws outward; the rest stay, so what leaves is crumbs, not a ring */
|
|
@@ -169,36 +114,104 @@ const MAX_RINGS = 5;
|
|
|
169
114
|
|
|
170
115
|
/** Per-frame values derived from the voice; every cell reads the same ones. */
|
|
171
116
|
type Voice = {
|
|
172
|
-
/** The voice inside its own range over about half a second (
|
|
117
|
+
/** The voice inside its own range over about half a second (live.tap createVoiceFollower) */
|
|
173
118
|
phrase: number;
|
|
119
|
+
/** The user's voice, the same measure, from the microphone (listening) */
|
|
120
|
+
micPhrase: number;
|
|
121
|
+
/** The same voice syllable by syllable, so a word shows and not only a sentence */
|
|
122
|
+
micLevel: number;
|
|
174
123
|
/** Spring kicked by each syllable */
|
|
175
124
|
bob: number;
|
|
176
125
|
bobVel: number;
|
|
177
126
|
/** Lobe strength and angle */
|
|
178
127
|
amp: number[];
|
|
179
128
|
phase: number[];
|
|
129
|
+
/** The whole pattern's turn (rad), one way */
|
|
130
|
+
spin: number;
|
|
180
131
|
/** One throw of crumbs per syllable */
|
|
181
132
|
rings: { born: number; power: number }[];
|
|
182
133
|
};
|
|
183
134
|
|
|
184
|
-
/**
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
135
|
+
/**
|
|
136
|
+
* Seconds each channel of the field takes to arrive, and to leave. Leaving is
|
|
137
|
+
* slower everywhere: a behaviour that stops winds down — crumbs already on their
|
|
138
|
+
* way keep coming and fade out — rather than vanishing on the frame the mode
|
|
139
|
+
* changes.
|
|
140
|
+
*/
|
|
141
|
+
const RISE = {
|
|
142
|
+
scale: 0.45,
|
|
143
|
+
lift: 0.22,
|
|
144
|
+
gather: 0.3,
|
|
145
|
+
comet: 0.45,
|
|
146
|
+
speech: 0.5,
|
|
147
|
+
err: 0.5,
|
|
148
|
+
};
|
|
149
|
+
const FALL = {
|
|
150
|
+
scale: 0.7,
|
|
151
|
+
lift: 0.4,
|
|
152
|
+
gather: 0.95,
|
|
153
|
+
comet: 0.9,
|
|
154
|
+
speech: 0.75,
|
|
155
|
+
err: 0.6,
|
|
156
|
+
};
|
|
157
|
+
/** Hanging up pulls the body in faster than anything else grows back. */
|
|
158
|
+
const END_FALL = 0.4;
|
|
159
|
+
|
|
160
|
+
/** Moves one channel toward its target; arriving and leaving have their own times. */
|
|
161
|
+
function toward(
|
|
162
|
+
from: number,
|
|
163
|
+
to: number,
|
|
164
|
+
rise: number,
|
|
165
|
+
fall: number,
|
|
166
|
+
dt: number,
|
|
167
|
+
) {
|
|
168
|
+
return from + (to - from) * Math.min(1, dt / (to > from ? rise : fall));
|
|
169
|
+
}
|
|
188
170
|
|
|
189
171
|
/**
|
|
190
|
-
*
|
|
191
|
-
* for SPEAK_MAX and the
|
|
192
|
-
* the
|
|
172
|
+
* The body every mode rests at. The max drawable radius is DESIGN/2, so this
|
|
173
|
+
* sets the budget for SPEAK_MAX and the crumbs thrown past it: leave room, or a
|
|
174
|
+
* loud voice fills the box and its swell has nowhere left to read. The visible
|
|
175
|
+
* body is about half, since the idle wave fades from 0.55 x IDLE_R.
|
|
193
176
|
*/
|
|
194
|
-
const IDLE_R =
|
|
177
|
+
const IDLE_R = 170;
|
|
195
178
|
|
|
196
|
-
/**
|
|
197
|
-
|
|
198
|
-
|
|
179
|
+
/**
|
|
180
|
+
* Connecting: crumbs travel in from the edge of the field to the resting body.
|
|
181
|
+
* Each ray carries its own crumb at its own phase, so nothing lines up into a
|
|
182
|
+
* ring.
|
|
183
|
+
*/
|
|
184
|
+
const GATHER_R = 320;
|
|
185
|
+
/** Equal sectors around the circle; each is a few cells wide, so its crumb reads as a crumb and not an arc */
|
|
186
|
+
const GATHER_RAYS = 56;
|
|
187
|
+
/** One crumb's trip inward, in trips per second */
|
|
188
|
+
const GATHER_RATE = 0.7;
|
|
189
|
+
/**
|
|
190
|
+
* Connecting draws the body in to `DIP` of its size and fills back out over
|
|
191
|
+
* `GROW` as the crumbs land in it, so the gathering has somewhere to go instead
|
|
192
|
+
* of piling onto a body that is already full.
|
|
193
|
+
*/
|
|
194
|
+
const GATHER_DIP = 0.45;
|
|
195
|
+
const GATHER_GROW = 1.3;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Listening: the resting body, its glyphs retyping as fast as the user speaks.
|
|
199
|
+
* Quiet is slower than idle, and a loud voice is PACE_VOICE times that; the
|
|
200
|
+
* shape never moves, which is the point.
|
|
201
|
+
*/
|
|
202
|
+
const LISTEN_PACE_QUIET = 0.5;
|
|
203
|
+
const LISTEN_PACE_VOICE = 8;
|
|
204
|
+
/**
|
|
205
|
+
* Brightness the voice adds: the field fills in as the user talks and thins out
|
|
206
|
+
* when they stop. Most of it follows the phrase so it holds through a sentence,
|
|
207
|
+
* the rest the syllable, so the words show without the body moving.
|
|
208
|
+
*/
|
|
209
|
+
const LISTEN_LIFT = 0.24;
|
|
210
|
+
/** Seconds the retype rate takes to follow the voice (toward) */
|
|
211
|
+
const PACE_TIME = 0.14;
|
|
199
212
|
|
|
200
|
-
/** Working: a comet orbiting just outside the
|
|
201
|
-
const WORK_R =
|
|
213
|
+
/** Working: a comet orbiting just outside the resting body */
|
|
214
|
+
const WORK_R = 210;
|
|
202
215
|
/** Orbit speed (rad/s); 3.0 is about one lap per 2s */
|
|
203
216
|
const WORK_SPIN = 3;
|
|
204
217
|
/** Orbit band width; larger blurs more */
|
|
@@ -230,10 +243,6 @@ type Cell = {
|
|
|
230
243
|
grain: number;
|
|
231
244
|
/** Below this brightness the cell is empty; random gaps */
|
|
232
245
|
gap: number;
|
|
233
|
-
/** Order this cell lights up when an expression appears (0..1) */
|
|
234
|
-
birth: number;
|
|
235
|
-
/** Order this cell goes out when an expression leaves; differs from birth */
|
|
236
|
-
death: number;
|
|
237
246
|
/** Emoji slot in emoji mode */
|
|
238
247
|
emoji: boolean;
|
|
239
248
|
/** Below SPECK_SHARE, a crumb a syllable throws outward */
|
|
@@ -262,28 +271,16 @@ function errorLetterAt(
|
|
|
262
271
|
return Math.floor(bx / 5);
|
|
263
272
|
}
|
|
264
273
|
|
|
265
|
-
/**
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
s: number,
|
|
273
|
-
) {
|
|
274
|
-
const bx = Math.floor(dx / (cw * s) + FACE_COLS / 2);
|
|
275
|
-
const by = Math.floor(dy / (ch * s) + FACE_ROWS / 2);
|
|
276
|
-
if (by < 0 || by >= FACE_ROWS || bx < 0 || bx >= FACE_COLS) return 0;
|
|
277
|
-
if (FACES[em][by][bx] !== "█") return 0;
|
|
278
|
-
return by < EYE_ROWS ? 1 : 2;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/** Idle: a soft breathing wave inside a small circle */
|
|
282
|
-
function idleValue(cell: Cell, t: number) {
|
|
283
|
-
const body = 1 - smoothstep(IDLE_R * 0.55, IDLE_R, cell.dist);
|
|
274
|
+
/**
|
|
275
|
+
* Idle: a soft breathing wave inside a small circle. `lift` brightens it in
|
|
276
|
+
* place; `scale` is the body's share of IDLE_R, which is how it opens and closes.
|
|
277
|
+
*/
|
|
278
|
+
function idleValue(cell: Cell, t: number, lift = 0, scale = 1) {
|
|
279
|
+
const r = IDLE_R * Math.max(0.02, scale);
|
|
280
|
+
const body = 1 - smoothstep(r * 0.55, r, cell.dist);
|
|
284
281
|
const w = Math.sin(cell.dist * 0.05 - t * 0.4);
|
|
285
282
|
const breath = Math.sin(t * 0.35) * 0.07;
|
|
286
|
-
return (0.58 + w * 0.2 + breath) * body;
|
|
283
|
+
return (0.58 + lift + w * 0.2 + breath) * body;
|
|
287
284
|
}
|
|
288
285
|
|
|
289
286
|
/** The rim's radius for a raw push: as pushed up to SPEAK_KNEE, then easing into SPEAK_MAX. */
|
|
@@ -294,142 +291,201 @@ function rimAt(raw: number) {
|
|
|
294
291
|
}
|
|
295
292
|
|
|
296
293
|
/**
|
|
297
|
-
*
|
|
298
|
-
*
|
|
294
|
+
* What the field is doing right now. A mode does not draw a picture of its own:
|
|
295
|
+
* it names targets for these channels, and each eases toward its target on its
|
|
296
|
+
* own clock, so a behaviour arrives and — when the mode changes — winds down.
|
|
299
297
|
*/
|
|
300
|
-
|
|
298
|
+
type Field = {
|
|
299
|
+
/** The body's radius as a share of IDLE_R; 0 is an empty field */
|
|
300
|
+
scale: number;
|
|
301
|
+
/** Brightness added to the body in place */
|
|
302
|
+
lift: number;
|
|
303
|
+
/** Crumbs streaming in from the edge of the field (connecting) */
|
|
304
|
+
gather: number;
|
|
305
|
+
/** A comet orbiting outside the body (working) */
|
|
306
|
+
comet: number;
|
|
307
|
+
/** Her voice: the rim it pushes and the crumbs a syllable throws (speaking) */
|
|
308
|
+
speech: number;
|
|
309
|
+
/** The ERROR letters */
|
|
310
|
+
err: number;
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
/** Where a mode wants the field. `e` is seconds since the mode was asked for. */
|
|
314
|
+
function targetFor(m: AsciiOrbMode, e: number, v: Voice): Field {
|
|
315
|
+
const rest: Field = {
|
|
316
|
+
scale: 1,
|
|
317
|
+
lift: 0,
|
|
318
|
+
gather: 0,
|
|
319
|
+
comet: 0,
|
|
320
|
+
speech: 0,
|
|
321
|
+
err: 0,
|
|
322
|
+
};
|
|
301
323
|
switch (m) {
|
|
302
324
|
case "idle":
|
|
303
|
-
return
|
|
325
|
+
return rest;
|
|
304
326
|
|
|
305
|
-
//
|
|
327
|
+
// draws in first, then fills back out as the crumbs land in it
|
|
306
328
|
case "connecting": {
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
0.2 +
|
|
315
|
-
hash(Math.floor(cell.dist / 9), Math.floor(cell.angle * 11)) * 0.85 +
|
|
316
|
-
hash(cell.seed * 137, 7) * 0.5;
|
|
317
|
-
const ring = band * grain * k;
|
|
318
|
-
return ring + idleValue(cell, t) * (1 - k);
|
|
329
|
+
const filled = 1 - Math.exp(-e / GATHER_GROW);
|
|
330
|
+
return {
|
|
331
|
+
...rest,
|
|
332
|
+
scale: GATHER_DIP + (1 - GATHER_DIP) * filled,
|
|
333
|
+
lift: 0.06 * filled,
|
|
334
|
+
gather: 1,
|
|
335
|
+
};
|
|
319
336
|
}
|
|
320
337
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
*/
|
|
328
|
-
case "speaking": {
|
|
329
|
-
const grow = smoothstep(0, 1, Math.min(1, e / 0.8));
|
|
330
|
-
|
|
331
|
-
let raw =
|
|
332
|
-
IDLE_R +
|
|
333
|
-
(SPEAK_BASE - IDLE_R + SPEAK_SWELL * v.phrase + SPEAK_KICK * v.bob) *
|
|
334
|
-
grow;
|
|
335
|
-
for (let i = 0; i < SPEAK_LOBES; i++) {
|
|
336
|
-
raw +=
|
|
337
|
-
SPEAK_LOBE_R *
|
|
338
|
-
v.amp[i] *
|
|
339
|
-
Math.sin((i + 2) * cell.angle + v.phase[i]) *
|
|
340
|
-
grow;
|
|
341
|
-
}
|
|
342
|
-
const edge = rimAt(raw);
|
|
343
|
-
|
|
344
|
-
// each cell sits a little in or out of the rim, and the offset drifts
|
|
345
|
-
const rough =
|
|
346
|
-
(cell.grain - 0.5) * SPEAK_ROUGH +
|
|
347
|
-
Math.sin(cell.angle * 5 + t * 0.9 + cell.seed * 6.283) *
|
|
348
|
-
SPEAK_ROUGH *
|
|
349
|
-
0.3;
|
|
350
|
-
const d = cell.dist - (edge + rough);
|
|
351
|
-
const rim = Math.exp(-(d * d) / 800);
|
|
352
|
-
const core = Math.exp(-(cell.dist * cell.dist) / 6000) * 0.5;
|
|
353
|
-
// a soft fill toward the center, with the idle wave still moving through it
|
|
354
|
-
const inside =
|
|
355
|
-
cell.dist < edge
|
|
356
|
-
? 0.3 *
|
|
357
|
-
(1 - cell.dist / edge) ** 0.6 *
|
|
358
|
-
(0.75 + 0.25 * Math.sin(cell.dist * 0.05 - t * 1.2))
|
|
359
|
-
: 0;
|
|
360
|
-
|
|
361
|
-
// crumbs: a sparse share of cells, each thrown past the rim at its own speed
|
|
362
|
-
let out = 0;
|
|
363
|
-
if (cell.speck < SPECK_SHARE) {
|
|
364
|
-
const speed = RING_SPEED * (0.6 + cell.grain * 0.9);
|
|
365
|
-
for (let i = 0; i < v.rings.length; i++) {
|
|
366
|
-
const ring = v.rings[i];
|
|
367
|
-
const age = t - ring.born;
|
|
368
|
-
const dd = cell.dist - (edge + 6 + age * speed);
|
|
369
|
-
out +=
|
|
370
|
-
Math.exp(-(dd * dd) / 500) *
|
|
371
|
-
ring.power *
|
|
372
|
-
Math.max(0, 1 - age / RING_LIFE);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
338
|
+
// the body holds still; the user's voice shows as ink and as the retype rate
|
|
339
|
+
case "listening":
|
|
340
|
+
return {
|
|
341
|
+
...rest,
|
|
342
|
+
lift: LISTEN_LIFT * (0.7 * v.micPhrase + 0.3 * v.micLevel),
|
|
343
|
+
};
|
|
375
344
|
|
|
376
|
-
|
|
377
|
-
|
|
345
|
+
case "speaking":
|
|
346
|
+
return { ...rest, speech: 1 };
|
|
378
347
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
* the voice and never ends.
|
|
382
|
-
*/
|
|
383
|
-
case "working": {
|
|
384
|
-
const k = smoothstep(0, 1, Math.min(1, e / 0.7));
|
|
348
|
+
case "working":
|
|
349
|
+
return { ...rest, comet: 1 };
|
|
385
350
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
const band = Math.exp(-(d * d) / WORK_BAND);
|
|
351
|
+
case "ending":
|
|
352
|
+
return { ...rest, scale: 0 };
|
|
389
353
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
354
|
+
case "error":
|
|
355
|
+
return { ...rest, scale: 0, err: 1 };
|
|
356
|
+
}
|
|
357
|
+
}
|
|
394
358
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
359
|
+
/** Crumbs traveling in from the edge of the field to the body's rim, dimming as they land. */
|
|
360
|
+
function gatherValue(cell: Cell, t: number, scale: number) {
|
|
361
|
+
const rim = IDLE_R * scale;
|
|
362
|
+
if (cell.speck >= 0.55 || cell.dist < rim * 0.8) return 0;
|
|
363
|
+
// atan2 reaches +PI, which would open a ray past the last one
|
|
364
|
+
const sector = Math.min(
|
|
365
|
+
GATHER_RAYS - 1,
|
|
366
|
+
Math.floor(((cell.angle + Math.PI) / (2 * Math.PI)) * GATHER_RAYS),
|
|
367
|
+
);
|
|
368
|
+
const ray = hash(sector, 5.3);
|
|
369
|
+
const p = (t * GATHER_RATE + ray) % 1;
|
|
370
|
+
const d =
|
|
371
|
+
cell.dist -
|
|
372
|
+
(rim + (GATHER_R - rim) * (1 - p) ** 1.25) -
|
|
373
|
+
(cell.grain - 0.5) * 16;
|
|
374
|
+
// dims as it lands, so a crumb is taken into the body rather than piling on it
|
|
375
|
+
return Math.exp(-(d * d) / 260) * smoothstep(0, 0.2, p) * (1 - p) * 1.1;
|
|
376
|
+
}
|
|
398
377
|
|
|
399
|
-
|
|
400
|
-
|
|
378
|
+
/** A comet on a thin orbit outside the body: sharp head, long tail. */
|
|
379
|
+
function cometValue(cell: Cell, t: number) {
|
|
380
|
+
const d = cell.dist - WORK_R;
|
|
381
|
+
const band = Math.exp(-(d * d) / WORK_BAND);
|
|
382
|
+
const raw = cell.angle - t * WORK_SPIN;
|
|
383
|
+
const da = Math.atan2(Math.sin(raw), Math.cos(raw));
|
|
384
|
+
return band * Math.exp(-(da * da) / (da < 0 ? WORK_TAIL : WORK_HEAD));
|
|
385
|
+
}
|
|
401
386
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
387
|
+
/**
|
|
388
|
+
* Her voice. Frequency is not mapped to angle: a voice's spectrum barely moves
|
|
389
|
+
* within a sentence, so that freezes into a fixed star. The voice gives the rim
|
|
390
|
+
* its size, its syllables and its lobes, and the whole pattern turns with time.
|
|
391
|
+
* No line in it is clean: the rim is crumbly, and a syllable throws crumbs
|
|
392
|
+
* rather than a ring.
|
|
393
|
+
*/
|
|
394
|
+
function speechValue(cell: Cell, t: number, v: Voice, amount: number) {
|
|
395
|
+
let raw = SPEAK_BASE + SPEAK_SWELL * v.phrase + SPEAK_KICK * v.bob;
|
|
396
|
+
for (let i = 0; i < SPEAK_LOBES; i++) {
|
|
397
|
+
raw +=
|
|
398
|
+
SPEAK_LOBE_R *
|
|
399
|
+
v.amp[i] *
|
|
400
|
+
Math.sin((i + 2) * (cell.angle + v.spin) + v.phase[i]);
|
|
401
|
+
}
|
|
402
|
+
// the rim grows out of the resting body as she starts and settles back into it
|
|
403
|
+
// when she stops; without this it appears at whatever the first syllable asks
|
|
404
|
+
// for, which reads as the circle jumping bigger
|
|
405
|
+
const edge = IDLE_R + (rimAt(raw) - IDLE_R) * amount;
|
|
406
|
+
|
|
407
|
+
// each cell sits a little in or out of the rim, and the offset drifts
|
|
408
|
+
const rough =
|
|
409
|
+
(cell.grain - 0.5) * SPEAK_ROUGH +
|
|
410
|
+
Math.sin(cell.angle * 5 + t * 0.9 + cell.seed * 6.283) * SPEAK_ROUGH * 0.3;
|
|
411
|
+
const d = cell.dist - (edge + rough);
|
|
412
|
+
let value =
|
|
413
|
+
Math.exp(-(d * d) / 800) + Math.exp(-(cell.dist * cell.dist) / 6000) * 0.5;
|
|
414
|
+
|
|
415
|
+
// a soft fill out to the rim, with the idle wave still moving through it
|
|
416
|
+
if (cell.dist < edge) {
|
|
417
|
+
value +=
|
|
418
|
+
0.22 *
|
|
419
|
+
(1 - cell.dist / edge) ** 0.6 *
|
|
420
|
+
(0.75 + 0.25 * Math.sin(cell.dist * 0.05 - t * 1.2));
|
|
421
|
+
}
|
|
405
422
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
(
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
const flick = 0.86 + Math.sin(t * 3.5 + cell.seed * 6) * 0.14;
|
|
418
|
-
return on * flick;
|
|
423
|
+
// crumbs: a sparse share of cells, each thrown past the rim at its own speed
|
|
424
|
+
if (cell.speck < SPECK_SHARE) {
|
|
425
|
+
const speed = RING_SPEED * (0.6 + cell.grain * 0.9);
|
|
426
|
+
for (let i = 0; i < v.rings.length; i++) {
|
|
427
|
+
const ring = v.rings[i];
|
|
428
|
+
const age = t - ring.born;
|
|
429
|
+
const dd = cell.dist - (edge + 6 + age * speed);
|
|
430
|
+
value +=
|
|
431
|
+
Math.exp(-(dd * dd) / 500) *
|
|
432
|
+
ring.power *
|
|
433
|
+
Math.max(0, 1 - age / RING_LIFE);
|
|
419
434
|
}
|
|
420
435
|
}
|
|
436
|
+
return value;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* ERROR, letter by letter: each lights up in turn and goes out the same way.
|
|
441
|
+
* `age` is ERROR's own clock, not the mode's, so leaving the mode fades the
|
|
442
|
+
* letters where they stand instead of restarting their cycle.
|
|
443
|
+
*/
|
|
444
|
+
function errorValue(cell: Cell, t: number, age: number) {
|
|
445
|
+
if (cell.letter < 0) return 0;
|
|
446
|
+
const pe = age % ERR_CYCLE;
|
|
447
|
+
const jitter = cell.seed * 0.12;
|
|
448
|
+
const appear = smoothstep(
|
|
449
|
+
0,
|
|
450
|
+
1,
|
|
451
|
+
(pe - cell.letter * ERR_STEP_IN - jitter) / ERR_FADE_IN,
|
|
452
|
+
);
|
|
453
|
+
const vanish = smoothstep(
|
|
454
|
+
0,
|
|
455
|
+
1,
|
|
456
|
+
(pe - ERR_HOLD_UNTIL - cell.letter * ERR_STEP_OUT - jitter) / ERR_FADE_OUT,
|
|
457
|
+
);
|
|
458
|
+
const flick = 0.86 + Math.sin(t * 3.5 + cell.seed * 6) * 0.14;
|
|
459
|
+
return Math.max(0, appear - vanish) * flick;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* One cell's brightness: the body, plus whichever behaviours are up. Her voice
|
|
464
|
+
* hollows the body rather than replacing it, so there is nothing to dissolve
|
|
465
|
+
* between when she starts or stops.
|
|
466
|
+
*/
|
|
467
|
+
function fieldValue(cell: Cell, t: number, errAge: number, f: Field, v: Voice) {
|
|
468
|
+
let value =
|
|
469
|
+
f.scale > 0.02
|
|
470
|
+
? idleValue(cell, t, f.lift, f.scale) * (1 - 0.6 * f.speech)
|
|
471
|
+
: 0;
|
|
472
|
+
if (f.gather > 0.01) value += gatherValue(cell, t, f.scale) * f.gather;
|
|
473
|
+
if (f.comet > 0.01) value += cometValue(cell, t) * f.comet;
|
|
474
|
+
if (f.speech > 0.01) value += speechValue(cell, t, v, f.speech) * f.speech;
|
|
475
|
+
if (f.err > 0.01) value += errorValue(cell, t, errAge) * f.err;
|
|
476
|
+
return value;
|
|
421
477
|
}
|
|
422
478
|
|
|
423
479
|
export function AsciiOrb({
|
|
424
480
|
className,
|
|
425
481
|
mode = "idle",
|
|
426
482
|
charset = ASCII_FACE.charset,
|
|
427
|
-
emotion = null,
|
|
428
483
|
fontSize = ASCII_FACE.fontSize.default,
|
|
429
484
|
density = ASCII_FACE.density.default,
|
|
430
485
|
size = DESIGN,
|
|
431
486
|
color = DEFAULT_COLOR,
|
|
432
487
|
getSpectrum,
|
|
488
|
+
getMicSpectrum,
|
|
433
489
|
}: AsciiOrbProps) {
|
|
434
490
|
const hostRef = useRef<HTMLCanvasElement>(null);
|
|
435
491
|
const ctxRef = useRef<CanvasRenderingContext2D | null>(null);
|
|
@@ -448,38 +504,42 @@ export function AsciiOrb({
|
|
|
448
504
|
cur: [...color] as [number, number, number],
|
|
449
505
|
target: color,
|
|
450
506
|
});
|
|
451
|
-
/**
|
|
452
|
-
const
|
|
453
|
-
cw: 1,
|
|
454
|
-
ch: 1,
|
|
455
|
-
errScale: 3,
|
|
456
|
-
faceScale: 3,
|
|
457
|
-
size: 0,
|
|
458
|
-
});
|
|
459
|
-
|
|
460
|
-
const emoRef = useRef<{
|
|
461
|
-
cur: AsciiOrbEmotion | null;
|
|
462
|
-
prev: AsciiOrbEmotion | null;
|
|
463
|
-
start: number;
|
|
464
|
-
}>({ cur: emotion, prev: null, start: -Infinity });
|
|
507
|
+
/** Side (px) the grid was built for; the loop clears this much */
|
|
508
|
+
const boxRef = useRef(0);
|
|
465
509
|
|
|
466
510
|
// the loop mounts once with no deps, so the latest getter comes through a ref
|
|
467
511
|
const specRef = useRef(getSpectrum);
|
|
468
512
|
specRef.current = getSpectrum;
|
|
513
|
+
const micRef = useRef(getMicSpectrum);
|
|
514
|
+
micRef.current = getMicSpectrum;
|
|
469
515
|
|
|
470
516
|
const voiceRef = useRef<Voice>({
|
|
471
517
|
phrase: 0,
|
|
518
|
+
micPhrase: 0,
|
|
519
|
+
micLevel: 0,
|
|
472
520
|
bob: 0,
|
|
473
521
|
bobVel: 0,
|
|
474
522
|
amp: new Array<number>(SPEAK_LOBES).fill(0),
|
|
475
523
|
// distinct start phases, or the lobes overlap into one lump at first
|
|
476
524
|
phase: Array.from({ length: SPEAK_LOBES }, (_, i) => i * 2.1),
|
|
525
|
+
spin: 0,
|
|
477
526
|
rings: [],
|
|
478
527
|
});
|
|
479
528
|
|
|
480
|
-
|
|
481
|
-
const
|
|
482
|
-
|
|
529
|
+
/** The mode being asked for, and when it was asked for. */
|
|
530
|
+
const modeRef = useRef({ mode, start: 0 });
|
|
531
|
+
/**
|
|
532
|
+
* The field on screen. It only ever eases toward the mode's targets, so it
|
|
533
|
+
* starts drawn in and opens on the first frames like any other arrival.
|
|
534
|
+
*/
|
|
535
|
+
const fieldRef = useRef<Field>({
|
|
536
|
+
scale: 0.3,
|
|
537
|
+
lift: 0,
|
|
538
|
+
gather: 0,
|
|
539
|
+
comet: 0,
|
|
540
|
+
speech: 0,
|
|
541
|
+
err: 0,
|
|
542
|
+
});
|
|
483
543
|
|
|
484
544
|
// grid is rebuilt only when size or density changes
|
|
485
545
|
useEffect(() => {
|
|
@@ -493,16 +553,12 @@ export function AsciiOrb({
|
|
|
493
553
|
const norm = DESIGN / size;
|
|
494
554
|
const cwN = cw * norm;
|
|
495
555
|
const chN = ch * norm;
|
|
496
|
-
// scale ERROR
|
|
556
|
+
// scale ERROR so it stays inside the box at any glyph size
|
|
497
557
|
const errScale = Math.max(
|
|
498
558
|
1,
|
|
499
559
|
Math.floor((DESIGN * 0.92) / (ERROR_BITMAP[0].length * cwN)),
|
|
500
560
|
);
|
|
501
|
-
|
|
502
|
-
1,
|
|
503
|
-
Math.floor((DESIGN * 0.82) / (FACE_COLS * cwN)),
|
|
504
|
-
);
|
|
505
|
-
metricsRef.current = { cw: cwN, ch: chN, errScale, faceScale, size };
|
|
561
|
+
boxRef.current = size;
|
|
506
562
|
|
|
507
563
|
const cells: Cell[] = [];
|
|
508
564
|
const cols = Math.ceil(size / cw);
|
|
@@ -531,9 +587,6 @@ export function AsciiOrb({
|
|
|
531
587
|
seed: hash(c, r),
|
|
532
588
|
grain: hash(c * 5.7 + 19, r * 2.3 + 53),
|
|
533
589
|
gap: 0.05 + hash(c * 7.3 + 11, r * 3.1 + 5) * 0.3,
|
|
534
|
-
// independent order per cell, so cells appear one at a time rather than in clumps
|
|
535
|
-
birth: hash(c * 3.1 + 7, r * 5.7 + 2),
|
|
536
|
-
death: hash(c * 9.4 + 3, r * 2.6 + 8),
|
|
537
590
|
emoji: hash(c * 2.7 + 31, r * 5.9 + 17) < EMOJI_RATIO,
|
|
538
591
|
speck: hash(c * 4.1 + 23, r * 6.3 + 41),
|
|
539
592
|
letter,
|
|
@@ -581,17 +634,6 @@ export function AsciiOrb({
|
|
|
581
634
|
};
|
|
582
635
|
}, [fontSize, density, size]);
|
|
583
636
|
|
|
584
|
-
// expression change: old one leaves, brief blank, new one appears
|
|
585
|
-
useEffect(() => {
|
|
586
|
-
const e = emoRef.current;
|
|
587
|
-
if (e.cur === emotion) return;
|
|
588
|
-
emoRef.current = {
|
|
589
|
-
cur: emotion,
|
|
590
|
-
prev: e.cur,
|
|
591
|
-
start: performance.now() * 0.001,
|
|
592
|
-
};
|
|
593
|
-
}, [emotion]);
|
|
594
|
-
|
|
595
637
|
// every frame redraws everything, so the charset only needs a ref update
|
|
596
638
|
useEffect(() => {
|
|
597
639
|
charsetRef.current = charset;
|
|
@@ -602,25 +644,26 @@ export function AsciiOrb({
|
|
|
602
644
|
colorRef.current.target = color;
|
|
603
645
|
}, [color]);
|
|
604
646
|
|
|
605
|
-
// mode change
|
|
647
|
+
// a mode change only moves the targets; the field eases the rest of the way
|
|
606
648
|
useEffect(() => {
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
prevRef.current = { ...curRef.current };
|
|
610
|
-
curRef.current = { mode, start: now };
|
|
611
|
-
xfadeStartRef.current = now;
|
|
612
|
-
} else {
|
|
613
|
-
curRef.current = { mode, start: now };
|
|
614
|
-
}
|
|
649
|
+
if (modeRef.current.mode === mode) return;
|
|
650
|
+
modeRef.current = { mode, start: performance.now() * 0.001 };
|
|
615
651
|
}, [mode]);
|
|
616
652
|
|
|
617
653
|
// animation loop
|
|
618
654
|
useEffect(() => {
|
|
619
655
|
let raf = 0;
|
|
620
656
|
const follower = createVoiceFollower();
|
|
657
|
+
const micFollower = createVoiceFollower();
|
|
621
658
|
const murmur = new Array<number>(SPECTRUM_BANDS).fill(0);
|
|
659
|
+
const silence = new Array<number>(SPECTRUM_BANDS).fill(0);
|
|
622
660
|
|
|
623
661
|
let lastT = performance.now() * 0.001;
|
|
662
|
+
/** Glyph clock: it runs at the retype pace, so changing the pace never jumps a glyph */
|
|
663
|
+
let clock = 0;
|
|
664
|
+
let pace = 1;
|
|
665
|
+
/** Seconds ERROR has been showing (errorValue) */
|
|
666
|
+
let errAge = 0;
|
|
624
667
|
|
|
625
668
|
const draw = (nowMs: number) => {
|
|
626
669
|
const t = nowMs * 0.001;
|
|
@@ -634,7 +677,7 @@ export function AsciiOrb({
|
|
|
634
677
|
return;
|
|
635
678
|
}
|
|
636
679
|
const cs = charsetRef.current;
|
|
637
|
-
const
|
|
680
|
+
const box = boxRef.current;
|
|
638
681
|
bk.asciiN.fill(0);
|
|
639
682
|
bk.emojiN.fill(0);
|
|
640
683
|
|
|
@@ -665,6 +708,19 @@ export function AsciiOrb({
|
|
|
665
708
|
voice.bobVel += -voice.bob * 0.012 - voice.bobVel * 0.09;
|
|
666
709
|
voice.bob += voice.bobVel;
|
|
667
710
|
|
|
711
|
+
// the microphone is read every frame but answers only while listening: it
|
|
712
|
+
// sets how fast the glyphs retype, and lifts the body across a phrase
|
|
713
|
+
const mic = micRef.current?.();
|
|
714
|
+
const micHeard = micFollower.read(mic ?? silence, dt);
|
|
715
|
+
voice.micPhrase = mic ? micHeard.phrase : 0;
|
|
716
|
+
voice.micLevel = mic ? micHeard.level : 0;
|
|
717
|
+
const wantPace =
|
|
718
|
+
mic && modeRef.current.mode === "listening"
|
|
719
|
+
? LISTEN_PACE_QUIET + LISTEN_PACE_VOICE * micHeard.level
|
|
720
|
+
: 1;
|
|
721
|
+
pace = toward(pace, wantPace, PACE_TIME, PACE_TIME, dt);
|
|
722
|
+
clock += dt * pace;
|
|
723
|
+
|
|
668
724
|
for (let i = 0; i < SPEAK_LOBES; i++) {
|
|
669
725
|
// neighbouring bands per lobe, low lobes from low bands
|
|
670
726
|
const from = Math.floor((i * heard.bands.length) / SPEAK_LOBES);
|
|
@@ -680,72 +736,45 @@ export function AsciiOrb({
|
|
|
680
736
|
// different time constants per harmonic, or the star only scales
|
|
681
737
|
voice.amp[i] += (energy * wander - voice.amp[i]) * (0.05 + i * 0.02);
|
|
682
738
|
// own speed, alternating direction, so no standing wave forms
|
|
683
|
-
voice.phase[i] += dt * (0.
|
|
739
|
+
voice.phase[i] += dt * (0.9 + i * 0.5) * (i % 2 ? -1 : 1);
|
|
684
740
|
}
|
|
685
741
|
|
|
742
|
+
// the pattern turns one way, faster while she is mid-phrase
|
|
743
|
+
voice.spin += dt * (SPEAK_SPIN + SPEAK_SPIN_VOICE * voice.phrase);
|
|
744
|
+
|
|
686
745
|
while (voice.rings.length > 0 && t - voice.rings[0].born > RING_LIFE) {
|
|
687
746
|
voice.rings.shift();
|
|
688
747
|
}
|
|
689
748
|
|
|
690
|
-
|
|
691
|
-
const
|
|
692
|
-
const
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
// expression state
|
|
702
|
-
const emo = emoRef.current;
|
|
703
|
-
const ep = t - emo.start;
|
|
704
|
-
// old one leaves cell by cell, blank, new one appears cell by cell
|
|
705
|
-
const rawOut = Math.min(1, Math.max(0, ep / FACE_OUT));
|
|
706
|
-
const rawIn = Math.min(
|
|
707
|
-
1,
|
|
708
|
-
Math.max(0, (ep - FACE_OUT - FACE_BLANK) / FACE_IN),
|
|
749
|
+
// the field eases toward what this mode wants, each channel on its own clock
|
|
750
|
+
const cur = modeRef.current;
|
|
751
|
+
const want = targetFor(cur.mode, t - cur.start, voice);
|
|
752
|
+
const f = fieldRef.current;
|
|
753
|
+
f.scale = toward(
|
|
754
|
+
f.scale,
|
|
755
|
+
want.scale,
|
|
756
|
+
RISE.scale,
|
|
757
|
+
cur.mode === "ending" ? END_FALL : FALL.scale,
|
|
758
|
+
dt,
|
|
709
759
|
);
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
Math.floor(cell.dy * 0.09 - t * 0.18),
|
|
724
|
-
) *
|
|
725
|
-
0.85;
|
|
726
|
-
return (s === 1 ? 1 : 0.88) * shade * holes;
|
|
727
|
-
};
|
|
728
|
-
|
|
729
|
-
/** A few specks of dust around the face, like idle */
|
|
730
|
-
const faceDust = (cell: Cell) => {
|
|
731
|
-
if (cell.seed < 0.976) return 0;
|
|
732
|
-
// each speck floats at its own distance so they do not line up in a band
|
|
733
|
-
const r = 195 + hash(cell.seed * 311, 9) * 160;
|
|
734
|
-
const fall = Math.exp(-((cell.dist - r) ** 2) / 7000);
|
|
735
|
-
// own blink rate and phase
|
|
736
|
-
const sp = 0.5 + hash(cell.seed * 47, 21) * 1.5;
|
|
737
|
-
return fall * (0.5 + 0.5 * Math.sin(t * sp + cell.seed * 300)) * 0.36;
|
|
738
|
-
};
|
|
760
|
+
f.lift = toward(f.lift, want.lift, RISE.lift, FALL.lift, dt);
|
|
761
|
+
f.gather = toward(f.gather, want.gather, RISE.gather, FALL.gather, dt);
|
|
762
|
+
f.comet = toward(f.comet, want.comet, RISE.comet, FALL.comet, dt);
|
|
763
|
+
f.speech = toward(f.speech, want.speech, RISE.speech, FALL.speech, dt);
|
|
764
|
+
// ERROR's clock runs only in its mode and holds while the letters fade
|
|
765
|
+
// out; an error that finds them already gone starts from the first letter
|
|
766
|
+
if (cur.mode === "error") {
|
|
767
|
+
if (f.err <= 0.01) errAge = 0;
|
|
768
|
+
errAge += dt;
|
|
769
|
+
}
|
|
770
|
+
f.err = toward(f.err, want.err, RISE.err, FALL.err, dt);
|
|
771
|
+
const keepGlyphSolid = f.err > 0.5;
|
|
772
|
+
const rate = cs === "emojiOnly" ? EMOJI_CHAR_RATE : CHAR_RATE;
|
|
739
773
|
|
|
740
774
|
const all = cellsRef.current;
|
|
741
775
|
for (let ci = 0; ci < all.length; ci++) {
|
|
742
776
|
const cell = all[ci];
|
|
743
|
-
let v =
|
|
744
|
-
|
|
745
|
-
if (blending && prev) {
|
|
746
|
-
const pv = valueFor(prev.mode, cell, t, t - prev.start, voice);
|
|
747
|
-
v = pv + (v - pv) * k;
|
|
748
|
-
}
|
|
777
|
+
let v = fieldValue(cell, t, errAge, f, voice);
|
|
749
778
|
|
|
750
779
|
if (!(keepGlyphSolid && cell.letter >= 0)) {
|
|
751
780
|
// per-cell brightness response breaks concentric rings; multiplicative, so empty (0) stays empty
|
|
@@ -770,38 +799,12 @@ export function AsciiOrb({
|
|
|
770
799
|
if (v < gate) v = 0;
|
|
771
800
|
}
|
|
772
801
|
|
|
773
|
-
// With an expression set, the whole field switches to it once the
|
|
774
|
-
// previous content (blob or old face) is fully gone
|
|
775
|
-
let solid = false;
|
|
776
|
-
if (faceBusy) {
|
|
777
|
-
// per-cell order with a narrow window: cells snap on and off rather than fade
|
|
778
|
-
const gone = smoothstep(0, 1, (rawOut * 1.1 - cell.death) / 0.08);
|
|
779
|
-
const born = smoothstep(0, 1, (rawIn * 1.1 - cell.birth) / 0.08);
|
|
780
|
-
|
|
781
|
-
// sample the bitmap once per expression
|
|
782
|
-
const kCur = emo.cur ? faceKind(emo.cur, cell) : 0;
|
|
783
|
-
const kPrev = emo.prev ? faceKind(emo.prev, cell) : 0;
|
|
784
|
-
|
|
785
|
-
const dust = faceDust(cell);
|
|
786
|
-
const oldV = emo.prev ? faceValue(kPrev, cell) + dust : v;
|
|
787
|
-
const newV = emo.cur ? faceValue(kCur, cell) + dust : v;
|
|
788
|
-
|
|
789
|
-
v = oldV * (1 - gone) + newV * born;
|
|
790
|
-
solid = (kCur > 0 && born > 0.05) || (kPrev > 0 && gone < 0.95);
|
|
791
|
-
}
|
|
792
|
-
|
|
793
802
|
v = v < 0 ? 0 : v > 1 ? 1 : v;
|
|
794
803
|
|
|
795
804
|
const level = (v * (RAMP.length - 1)) | 0;
|
|
796
805
|
if (level === 0) continue;
|
|
797
806
|
|
|
798
|
-
|
|
799
|
-
const rate = solid
|
|
800
|
-
? FACE_CHAR_RATE
|
|
801
|
-
: cs === "emojiOnly"
|
|
802
|
-
? EMOJI_CHAR_RATE
|
|
803
|
-
: CHAR_RATE;
|
|
804
|
-
const slot = (t * rate + cell.seed * 7) | 0;
|
|
807
|
+
const slot = (clock * rate + cell.seed * 7) | 0;
|
|
805
808
|
|
|
806
809
|
const showEmoji =
|
|
807
810
|
cs === "emojiOnly" ||
|
|
@@ -859,8 +862,6 @@ export function AsciiOrb({
|
|
|
859
862
|
}
|
|
860
863
|
ctx.globalAlpha = 1;
|
|
861
864
|
|
|
862
|
-
if (!blending && prev) prevRef.current = null;
|
|
863
|
-
|
|
864
865
|
raf = requestAnimationFrame(draw);
|
|
865
866
|
};
|
|
866
867
|
|