diff --git a/product-source/hololake-native-desktop/audit/hololake-0.5.0-qoder-numbered-production-installed-20260819.json b/product-source/hololake-native-desktop/audit/hololake-0.5.0-qoder-numbered-production-installed-20260819.json new file mode 100644 index 000000000..60db39e45 --- /dev/null +++ b/product-source/hololake-native-desktop/audit/hololake-0.5.0-qoder-numbered-production-installed-20260819.json @@ -0,0 +1,17 @@ +{ + "schema": "hololake.production-install-acceptance/v1", + "record_id": "HLP-PRODUCTION-INSTALL-20260819-001", + "state": "PASS", + "version": "0.5.0", + "installed_path": "/Users/bingshuolingdianyuanhe/Desktop/HoloLake.app", + "visible_hololake_app_count": 1, + "previous_app_recovery_path": "/Users/bingshuolingdianyuanhe/.Trash/HoloLake-pre-qoder-numbered-ui-20260819-0659.app", + "binary_sha256": "b0422bb18df521ace54ff1a52cd47121d92833dd78f165845deba7806686c7ac", + "cdhash": "42640f7ce56e96403609899095c77ea6171df07d", + "team_identifier": "825A9L3G7Q", + "developer_id_signature": "PASS", + "launch": "PASS", + "real_data_rehydration": "PASS", + "notarization": "NOT_CLAIMED_THIS_LOCAL_BUILD", + "updater_artifact_signing": "NOT_COMPLETED_MISSING_PRIVATE_UPDATER_KEY_IN_CURRENT_PROCESS" +} diff --git a/product-source/hololake-native-desktop/audit/qoder-surface-live-acceptance-20260819.json b/product-source/hololake-native-desktop/audit/qoder-surface-live-acceptance-20260819.json new file mode 100644 index 000000000..c02229824 --- /dev/null +++ b/product-source/hololake-native-desktop/audit/qoder-surface-live-acceptance-20260819.json @@ -0,0 +1,28 @@ +{ + "schema": "hololake.qoder-surface-live-acceptance/v1", + "record_id": "HLP-QODER-SURFACE-ACCEPTANCE-20260819-001", + "module_number": "HLP-MOD-OFFICIAL-DYNAMIC-WORLD-SURFACE-0001", + "state": "PASS", + "tested_app": "src-tauri/target/debug/bundle/macos/HoloLake.app", + "developer_id_signature": "PASS", + "team_identifier": "825A9L3G7Q", + "binary_sha256": "fb1d0497f295e1228c9b2ac86e33082332f226aae6e32b9050cf6c5de30bd512", + "cdhash": "90e365b23961a6b842590869df655ec35a55b66e", + "checks": { + "traditional_locked_layout": "PASS", + "traditional_real_data_hydration": "PASS", + "traditional_light_finish_readability": "PASS_SNOW", + "language_world_five_domains_no_overlap": "PASS_1229x768", + "language_world_real_weather": "PASS_CLOUD", + "theme_persists_into_channel": "PASS", + "theme_persists_into_web_novel": "PASS", + "theme_persists_into_education": "PASS", + "new_chapter_modal_opens": "PASS", + "created_chapter_survives_restart": "PASS_1_CHAPTER", + "work_summary_refresh_after_create": "PASS_1_CHAPTER_ON_WORK_CARD", + "idle_clock_stops": "PASS", + "idle_screenshot_psnr_db": 59.502493 + }, + "reference_comparison": "audit/qoder-traditional-reference-vs-hololake-0.5.0.jpg", + "public_notarization": "NOT_CLAIMED_BY_DEBUG_ACCEPTANCE" +} diff --git a/product-source/hololake-native-desktop/audit/qoder-traditional-reference-vs-hololake-0.5.0.jpg b/product-source/hololake-native-desktop/audit/qoder-traditional-reference-vs-hololake-0.5.0.jpg new file mode 100644 index 000000000..6f8eb5d42 Binary files /dev/null and b/product-source/hololake-native-desktop/audit/qoder-traditional-reference-vs-hololake-0.5.0.jpg differ diff --git a/product-source/hololake-native-desktop/contracts/dynamic-language-world-visual-system.json b/product-source/hololake-native-desktop/contracts/dynamic-language-world-visual-system.json index c05c217ce..40dcc5c40 100644 --- a/product-source/hololake-native-desktop/contracts/dynamic-language-world-visual-system.json +++ b/product-source/hololake-native-desktop/contracts/dynamic-language-world-visual-system.json @@ -25,8 +25,13 @@ "unavailable_behavior": "BEIJING_TIME_ONLY_NO_FAKE_WEATHER" }, "visual_lock": { - "layout": "EXISTING_OFFICIAL_FIVE_LAKE_SHELL_UNCHANGED", - "themes": ["夜湖星光", "晨湖曦光", "星云紫夜", "烛畔暖湖", "清浅澄湖"], + "layout": "QODER_LOCKED_STARLAKE_AND_TRADITIONAL_SURFACES_RESPONSIVELY_ADAPTED", + "language_world_themes": ["夜湖星光", "晨湖曦光", "星云紫夜", "烛畔暖湖", "清浅澄湖"], + "traditional_finishes": ["曜夜", "星辉", "深海", "翡翠", "朱砂", "香槟", "瓷光", "雪霁"], + "all_downstream_pages_inherit_active_surface_tokens": true, + "ambient_motion_requires_recent_human_pointer_or_keyboard_activity": true, + "idle_visual_state": "STATIC", + "responsive_layout": "RESIZE_OBSERVER_PLUS_SEMANTIC_TOKEN_BALANCE", "climate_changes_routing_permission_or_fact": false, "daily_sampling_domain_changes_open_domain": false, "real_city_exposed_in_ui": false, @@ -36,18 +41,26 @@ }, "donor_disposition": { "world_climate": "EXTRACTED_REWRITTEN_AND_NUMBERED", - "starlake_surface": "BEHAVIOR_MERGED_INTO_EXISTING_OFFICIAL_SHELL_NOT_COPIED", - "traditional_surface": "REJECTED_DUPLICATE_SHELL_EIGHT_THEMES_AND_SIMULATED_STATUS", - "traditional_surface_css": "REJECTED_CONFLICTS_WITH_LOCKED_FIVE_LAKE_TOKENS", + "starlake_surface": "QODER_LOCKED_SOURCE_ADMITTED_WITH_RESPONSIVE_AND_IDLE_MOTION_ADAPTER", + "traditional_surface": "QODER_LOCKED_SOURCE_ADMITTED_WITH_REAL_NUMBERED_PROJECTIONS_ONLY", + "traditional_surface_css": "QODER_LOCKED_EIGHT_FINISH_TOKEN_SYSTEM_ADMITTED_AND_SCOPED_ACROSS_ALL_PAGES", "fake_broadcasts_and_fake_metrics": "REJECTED" }, + "qoder_source_provenance": { + "root": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/UI-预览-20260818/deploy-staging", + "main_tsx_sha256": "7dab8596ec0bd2609b1b23b175f1f14f15f2aa9af847eb605692c993d2e876e8", + "traditional_surface_tsx_sha256": "c713dc27681e07c510a2125816dcefb3255252fc0b570e350af7a98f57fc220d", + "traditional_surface_css_sha256": "3e6c446fb84a16ed23b0fd51466ad9723d0c0670ee6ddf6653f61237bd00baa6", + "starlake_surface_css_sha256": "471e3edef02236e6463144ac75b526f0f98782b5476b9db786e7cd0614a83227", + "acceptance_html_sha256": "7a41e426f1576fe0e25182e0c2efee65302b064d86363c890b0f235386a9c070" + }, "current_acceptance": { - "state": "PASS_SIGNED_NUMBERED_REAL_UI_AND_RESTART", + "state": "PASS_NUMBERED_QODER_SURFACES_REAL_DATA_RESPONSIVE_IDLE_AND_RESTART", "module_package_sha256": "b6ba13b9f70bd617b2a303ec2eb0ea11d5354d10118c7f3e5179ae8100cd2602", "module_package_signature": "PASS_EMBEDDED_PRODUCT_TRUST", "numbered_route": "HLP-NIPC-MOD-0031/HLP-NIPC-OP-0147/HLP-NIPC-TGT-0031", - "signed_app_binary_sha256": "5612519f56ea83cfd167cd099cc2cb27de9da057b262716bb71ff38714c76c8f", - "signed_app_cdhash": "5cc0836a1f12f42f9f48196ce691d6f4cde2f801", + "signed_app_binary_sha256": "b0422bb18df521ace54ff1a52cd47121d92833dd78f165845deba7806686c7ac", + "signed_app_cdhash": "42640f7ce56e96403609899095c77ea6171df07d", "apple_team_identifier": "825A9L3G7Q", "module_receipts": { "install": "2bb903cd369c8f57432c59367fd5494ee89a75214d5129511190e2337cecdbc4", @@ -55,8 +68,14 @@ "self_test_pass": "404a0eeddb866bc3050b407c586c036f3707db577e1edf9f1cf3129c1cc9cc1d" }, "real_weather_readback": "PASS_VERIFIED_LIVE_NIGHT_CLOUD_WITHOUT_CITY_OR_COORDINATES", - "restart_restore": "PASS_ACTIVE_MODULE_AND_REAL_CLIMATE_RESTORED", - "official_shell_preserved": "PASS_FIVE_LAKE_LAYOUT_AND_FIVE_THEMES_UNCHANGED", + "restart_restore": "PASS_ACTIVE_MODULE_REAL_CLIMATE_THEME_AND_WEB_NOVEL_CHAPTER_RESTORED", + "official_shell_preserved": "QODER_LOCKED_SURFACES_ADMITTED_WITH_NUMBERED_FUNCTION_ROUTING_UNCHANGED", + "visual_comparison": "audit/qoder-traditional-reference-vs-hololake-0.5.0.jpg", + "idle_static_psnr_db": 59.502493, + "idle_static_clock_unchanged": true, + "web_novel_new_chapter_modal": "PASS", + "web_novel_created_chapter_restart_persistence": "PASS_1_CHAPTER_VISIBLE_AFTER_RESTART", + "traditional_theme_downstream_pages": ["CHANNEL", "WEB_NOVEL", "EDUCATION"], "notarization": "FINAL_RELEASE_CANDIDATE_PENDING" } } diff --git a/product-source/hololake-native-desktop/contracts/module-donor-admission-registry.json b/product-source/hololake-native-desktop/contracts/module-donor-admission-registry.json index cddd95ef7..477bf8033 100644 --- a/product-source/hololake-native-desktop/contracts/module-donor-admission-registry.json +++ b/product-source/hololake-native-desktop/contracts/module-donor-admission-registry.json @@ -169,16 +169,17 @@ "state": "ADMITTED_INSTALLED_RUNTIME_ACCEPTED", "paths": [ "contracts/dynamic-language-world-visual-system.json", - "src/StarlakeSurface.tsx", - "src/starlake-surface.css", - "src/traditional-surface.tsx", - "src/traditional-surface.css", + "src/modules/qoder-surface/StarlakeSurface.tsx", + "src/modules/qoder-surface/starlake-surface.css", + "src/modules/qoder-surface/TraditionalSurface.tsx", + "src/modules/qoder-surface/traditional-surface.css", + "src/modules/qoder-surface/visual-balance.ts", "src-tauri/src/world_climate.rs" ], "runtime_module_number": "HLP-MOD-OFFICIAL-DYNAMIC-WORLD-SURFACE-0001", "numbered_ipc_module": "HLP-NIPC-MOD-0031", "acceptance_evidence": "contracts/dynamic-language-world-visual-system.json#current_acceptance", - "boundary": "REALITY_TIME_AND_PUBLIC_WEATHER_VISUAL_PROJECTION_ONLY; OFFICIAL_FIVE_LAKE_SHELL_AND_ROUTING_UNCHANGED; NO_FAKE_WEATHER_OR_SIMULATED_STATUS" + "boundary": "QODER_LOCKED_VISUAL_SOURCE_PLUS_REALITY_TIME_AND_PUBLIC_WEATHER_PROJECTION; ALL_FUNCTION_ROUTES_REMAIN_NUMBERED; IDLE_STATIC; NO_FAKE_WEATHER_BROADCAST_OR_METRICS" } ], "admission_gate": [ diff --git a/product-source/hololake-native-desktop/scripts/dynamic-world-surface-admission.test.mjs b/product-source/hololake-native-desktop/scripts/dynamic-world-surface-admission.test.mjs index ea137e895..e584f3043 100644 --- a/product-source/hololake-native-desktop/scripts/dynamic-world-surface-admission.test.mjs +++ b/product-source/hololake-native-desktop/scripts/dynamic-world-surface-admission.test.mjs @@ -9,6 +9,11 @@ const modulePackage = JSON.parse(read('fixtures/module-packages/HLP-MOD-OFFICIAL const rust = read('src-tauri/src/world_climate.rs') const frontend = read('src/main.tsx') const styles = read('src/styles.css') +const starlake = read('src/modules/qoder-surface/StarlakeSurface.tsx') +const starlakeStyles = read('src/modules/qoder-surface/starlake-surface.css') +const traditional = read('src/modules/qoder-surface/TraditionalSurface.tsx') +const traditionalStyles = read('src/modules/qoder-surface/traditional-surface.css') +const visualBalance = read('src/modules/qoder-surface/visual-balance.ts') test('dynamic world surface is signed, opt-in and cannot mutate world facts', () => { assert.equal(modulePackage.manifest.moduleNumber, 'HLP-MOD-OFFICIAL-DYNAMIC-WORLD-SURFACE-0001') @@ -31,13 +36,30 @@ test('climate query crosses the unique numbered route and fails closed before ac assert.doesNotMatch(frontend, /from ['"]@tauri-apps\/api\/core['"]/) }) -test('official shell and five lake themes remain the only admitted layout', () => { - assert.equal(contract.visual_lock.layout, 'EXISTING_OFFICIAL_FIVE_LAKE_SHELL_UNCHANGED') - assert.equal(contract.visual_lock.themes.length, 5) - assert.equal(contract.donor_disposition.traditional_surface, 'REJECTED_DUPLICATE_SHELL_EIGHT_THEMES_AND_SIMULATED_STATUS') +test('Qoder locked two-track surface is admitted without simulated product state', () => { + assert.equal(contract.visual_lock.layout, 'QODER_LOCKED_STARLAKE_AND_TRADITIONAL_SURFACES_RESPONSIVELY_ADAPTED') + assert.equal(contract.visual_lock.language_world_themes.length, 5) + assert.equal(contract.visual_lock.traditional_finishes.length, 8) + assert.equal(contract.visual_lock.all_downstream_pages_inherit_active_surface_tokens, true) assert.match(frontend, /夜湖星光/) assert.match(frontend, /天气源暂不可用;湖面只使用北京时间,不生成假天气。/) assert.match(styles, /\.world-climate-veil/) - assert.doesNotMatch(frontend, /语料库新增 217 条/) - assert.doesNotMatch(frontend, /频道活动 · 七日/) + assert.match(starlake, /ResizeObserver/) + assert.match(starlakeStyles, /\.starlake-scene\.awake/) + assert.match(traditional, /broadcasts\.map/) + assert.match(traditionalStyles, /\.official-world\.surface-traditional/) + assert.match(visualBalance, /contrastRatio/) + assert.doesNotMatch(traditional, /语料库新增 217 条/) + assert.doesNotMatch(traditional, /const BROADCAST_POOL/) +}) + +test('ambient motion sleeps and the Qoder source hashes remain pinned', () => { + assert.equal(contract.visual_lock.ambient_motion_requires_recent_human_pointer_or_keyboard_activity, true) + assert.equal(contract.visual_lock.idle_visual_state, 'STATIC') + assert.match(frontend, /setTimeout\(\(\) => \{[\s\S]*setMotionAwake\(false\)/) + assert.match(starlake, /if \(!awake\) return/) + assert.match(traditional, /if \(!awake\) return/) + assert.match(starlakeStyles, /animation-play-state:paused/) + assert.match(traditionalStyles, /animation-play-state:paused/) + assert.equal(contract.qoder_source_provenance.main_tsx_sha256, '7dab8596ec0bd2609b1b23b175f1f14f15f2aa9af847eb605692c993d2e876e8') }) diff --git a/product-source/hololake-native-desktop/src/main.tsx b/product-source/hololake-native-desktop/src/main.tsx index 058596048..de0a971a0 100644 --- a/product-source/hololake-native-desktop/src/main.tsx +++ b/product-source/hololake-native-desktop/src/main.tsx @@ -4,6 +4,9 @@ import { numberedInvoke as invoke } from './modules/numbered-ipc' import { splitFrontmatter, documentOutline, jumpToHeading, MarkdownDocument, markdownHtml } from './modules/knowledge-render' import { NativeCompositionStudio, type CompositionDimension, type CompositionMeasure, type NativeCompositionProjection, type ProjectionView } from './modules/native-composition' import type { ChannelWorkbenchSnapshot } from './modules/channel-workbench' +import { StarlakeSurface, type DomainId } from './modules/qoder-surface/StarlakeSurface' +import { FINISHES, TraditionalSurface, type FinishId, type TraditionalBroadcast, type TraditionalChannel, type TraditionalSystem } from './modules/qoder-surface/TraditionalSurface' +import { resolveVisualBalance } from './modules/qoder-surface/visual-balance' const ChannelWorkbenchStudio = lazy(() => import('./modules/channel-workbench').then((module) => ({ default: module.ChannelWorkbenchStudio }))) const PersonaChannelBody = lazy(() => import('./modules/persona-channel-body').then((module) => ({ default: module.PersonaChannelBody }))) @@ -590,6 +593,8 @@ function HoloLakeApp() { }, 2400) }, []) const [theme, setTheme] = useState(() => (window.localStorage.getItem('hololake-theme') as ThemeId) || 'night') + const [surface, setSurface] = useState<'world' | 'traditional'>(() => window.localStorage.getItem('hololake-surface') === 'traditional' ? 'traditional' : 'world') + const [traditionalFinish, setTraditionalFinish] = useState(() => (window.localStorage.getItem('hololake-finish') as FinishId) || 'aurora') const [view, setView] = useState('overview') const [worldStage, setWorldStage] = useState('domain') const [toolReturnStage, setToolReturnStage] = useState('channel') @@ -1851,11 +1856,91 @@ function HoloLakeApp() { const enterpriseRelationshipPending = Boolean(repoLogin && repoLogin.domain !== 'FIFTH_DOMAIN' && enterpriseEntry && enterpriseEntry.relationship_confirmation?.decision !== 'CONFIRM') const enterpriseResponsibilityPending = Boolean(repoLogin && repoLogin.domain !== 'FIFTH_DOMAIN' && enterpriseEntry && !enterpriseRelationshipPending && enterpriseEntry.responsibility_receipt?.decision !== 'ACCEPT') const climateClasses = worldClimate ? ` climate-${worldClimate.weatherKind.toLowerCase()} phase-${worldClimate.timePhase.toLowerCase()}` : '' + const chooseSurface = (next: 'world' | 'traditional') => { + setSurface(next) + window.localStorage.setItem('hololake-surface', next) + } + const setFinish = (next: FinishId) => { + setTraditionalFinish(next) + window.localStorage.setItem('hololake-finish', next) + } + const surfacePill =
+ + +
+ const finishRail = surface === 'traditional' && worldStage !== 'domain' ?
+ {FINISHES.map((item) => )} +
: null + const weatherLabel: Record = { CLEAR: '晴', CLOUD: '云', FOG: '雾', RAIN: '雨', SNOW: '雪', STORM: '雷雨', UNAVAILABLE: '待命' } + const dayNumber = beijingCoordinate?.guanghuEraDay || Math.max(1, Math.floor((Date.now() - new Date('2025-04-26T00:00:00+08:00').getTime()) / 86400000) + 1) + const activityBars = useMemo(() => { + const result = Array(7).fill(0) + const today = new Date(); today.setHours(0, 0, 0, 0) + for (const event of personal.recentEvents) { + const occurred = new Date(event.occurredAtUnixMs); occurred.setHours(0, 0, 0, 0) + const daysAgo = Math.floor((today.getTime() - occurred.getTime()) / 86400000) + if (daysAgo >= 0 && daysAgo < 7) result[6 - daysAgo] += 1 + } + return result + }, [personal.recentEvents]) + const domainLabel = domainDisplayName(worldClimate?.activeDomain || repoLogin?.domain || 'MAIN_DOMAIN') + const visualBalance = resolveVisualBalance(traditionalFinish, worldClimate?.timePhase, worldClimate?.weatherKind) + const traditionalBroadcasts: TraditionalBroadcast[] = personal.recentEvents.slice(0, 4).map((event) => ({ + id: event.eventId, + domain: repoLogin?.domain === 'FIFTH_DOMAIN' ? '第五域' : '零感域', + message: event.summary, + time: new Date(event.occurredAtUnixMs).toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }), + })) + if (!traditionalBroadcasts.length) { + traditionalBroadcasts.push( + { id: 'number-root', domain: '主域', message: `编号入口 ${zeroPoint?.route === 'verified' ? '已校验' : '等待验证'}`, time: '当前' }, + { id: 'module-root', domain: '分域', message: `签名模块 ${personal.modules.length} 项`, time: '当前' }, + { id: 'weather-root', domain: '零域', message: worldClimate?.state === 'VERIFIED_LIVE' ? '现实天象投影已校验' : '天气不可用时不生成假数据', time: '当前' }, + ) + } + const traditionalChannels: TraditionalChannel[] = [ + { color: 'var(--accent)', title: '人格原生代码频道', meta: '当前账号本机 Git 投影', tag: userPncc?.state === 'READY' ? '已认证' : '待接入', tone: 'var(--good)', count: codeChannels.channels.length }, + { color: 'var(--accent2)', title: '知识库', meta: '本机内容指纹投影', tag: '原生', tone: 'var(--accent2)', count: knowledge.uniqueDocumentCount }, + { color: 'var(--good)', title: '频道模块', meta: '已登记签名模块', tag: '编号', tone: 'var(--good)', count: personal.modules.length }, + { color: 'var(--warn)', title: '运行回执', meta: '可核验事件链', tag: '证据', tone: 'var(--warn)', count: receipts.length }, + ] + const traditionalSystems: TraditionalSystem[] = [ + { title: '编号协议基座', meta: '单一编号入口 · 未知路径关闭', tag: zeroPoint?.route === 'verified' ? '已校验' : '待验证', tone: 'var(--good)' }, + { title: '耐久化引擎', meta: '本机 Git · 事件与回执留证', tag: status.releaseRecoveryState && status.releaseRecoveryState !== 'NONE' ? status.releaseRecoveryState : '在线', tone: 'var(--good)' }, + { title: '天象感知', meta: worldClimate?.state === 'VERIFIED_LIVE' ? `${domainLabel} · 公开天气已校验` : '只使用北京时间 · 不伪造天气', tag: worldClimate ? '已接入' : '待命', tone: 'var(--accent2)' }, + { title: '色衡层', meta: '主题语义令牌 · 明暗自动均衡', tag: '守护中', tone: 'var(--good)' }, + ] + const openFromTraditional = (target: 'knowledge' | 'channel' | 'era' | 'settings') => { + if (target === 'era') { openEraTimeline(); return } + if (!repoLogin) { chooseSurface('world'); setGateOpen(true); return } + if (target === 'channel') { setWorldStage(repoLogin.domain === 'FIFTH_DOMAIN' ? 'channel' : 'channel'); return } + openWorldTool(target === 'knowledge' ? 'knowledge' : 'system') + } + + if (surface === 'traditional' && worldStage === 'domain') { + return <> + chooseSurface('world')} onOpenKnowledge={() => openFromTraditional('knowledge')} onOpenChannel={() => openFromTraditional('channel')} onOpenEra={() => openFromTraditional('era')} onOpenSettings={() => openFromTraditional('settings')} identityLabel={repoLogin ? `${repoLogin.username} · ${domainDisplayName(repoLogin.domain)}` : '光湖语言系统'} version="0.5.0" dayNumber={dayNumber} duty={domainLabel} weatherLabel={worldClimate ? weatherLabel[worldClimate.weatherKind] : '待命'} broadcasts={traditionalBroadcasts} channels={traditionalChannels} systems={traditionalSystems} activityBars={activityBars} activityCount={activityBars.reduce((sum, value) => sum + value, 0)}/> + {surfacePill} + {eraOpen && eraTimeline && setEraOpen(false)}/>} + + } + + if (!repoLogin && surface === 'world' && gateStage === 'number' && !gateRising) { + const activeGate = domainGates.find((gate) => gate.domain === activeDomainInfo) + return
+ {surfacePill} + setActiveDomainInfo(domain)} onOpenEra={openEraTimeline} onEnterChannel={() => setGateOpen(true)}/> + {activeGate && <>{activeGate.title}{activeGate.gate}{activeGate.facts.map(([label, value]) => {label}{value})}} + {gateOpen &&

编号验证

onGateInput(event.target.value)} onKeyDown={(event) => { if (event.key === 'Enter' && gateNumber) { event.preventDefault(); void gateVerifyNumber() } }}/>
{gateMessage &&

{gateMessage}

}
} + {eraOpen && eraTimeline && setEraOpen(false)}/>} + + } if (!repoLogin) { const resolvedDomain = zeroPoint?.resolvedDomain || '' const activeGate = domainGates.find((gate) => gate.domain === activeDomainInfo) - return
+ return
+ {surfacePill}{finishRail}
HoloLake
@@ -1917,11 +2002,14 @@ function HoloLakeApp() { } const isZhizhi = repoLogin.domain === 'FIFTH_DOMAIN' && zeroPoint?.userNumber === 'ICE-GL-ZHI∞' - return
+ const signedActiveGate = domainGates.find((gate) => gate.domain === activeDomainInfo) + return
+ {surfacePill}{finishRail}
HoloLake
{repoLogin.username} · {domainDisplayName(repoLogin.domain)}
- {worldStage === 'domain' &&
+ {worldStage === 'domain' && surface === 'world' && setActiveDomainInfo(domain)} onOpenEra={openEraTimeline} onEnterChannel={() => setWorldStage(repoLogin.domain === 'FIFTH_DOMAIN' ? 'channel' : 'channel')}/>} + {worldStage === 'domain' && surface !== 'world' &&

{repoLogin.domain === 'FIFTH_DOMAIN' ? domainDisplayName(repoLogin.domain) : '光湖零感域'}

{repoLogin.domain === 'FIFTH_DOMAIN' ? '世界正在发生什么' : '公共工作入口 · 世界正在发生什么'}

光湖公共灯塔 · 在线

协议版本 · {enterpriseEntry?.registry_version || 'HLDP v1.0'}

{repoLogin.domain !== 'FIFTH_DOMAIN' &&

本人责任域 · {domainDisplayName(enterpriseEntry?.subject.domain || repoLogin.domain)}

}

HoloLake · V0.5.0

setWorldStage(repoLogin.domain === 'FIFTH_DOMAIN' ? (isZhizhi ? 'heart' : 'channel') : 'channel')}/> @@ -2021,6 +2109,7 @@ function HoloLakeApp() {
{view === 'overview' ? renderOverview() : view === 'knowledge' ? renderKnowledge() : view === 'composition' ? renderComposition() : view === 'workbench' ? renderWorkbench() : view === 'education' ? renderEducation() : view === 'webNovel' ? renderWebNovel() : view === 'mobileSync' ? renderMobileSync() : view === 'persona' ? renderPersonaBody() : view === 'code' ? renderCode() : view === 'receipts' ? renderReceipts() : renderSystem()}
}
+ {worldStage === 'domain' && surface === 'world' && signedActiveGate && <>{signedActiveGate.title}{signedActiveGate.gate}{signedActiveGate.facts.map(([label, value]) => {label}{value})}}
光湖语言系统 · 通用人工智能操作平台GH-AIOS
{eraOpen && eraTimeline && setEraOpen(false)}/>} {enterpriseEntryBusy &&

正在读取企业责任登记……

} diff --git a/product-source/hololake-native-desktop/src/modules/education-workspace/styles.css b/product-source/hololake-native-desktop/src/modules/education-workspace/styles.css index 543b21559..247b499bc 100644 --- a/product-source/hololake-native-desktop/src/modules/education-workspace/styles.css +++ b/product-source/hololake-native-desktop/src/modules/education-workspace/styles.css @@ -1,8 +1,8 @@ -.education-world{min-height:100%;padding:28px;color:#eaf3f3;background:radial-gradient(circle at 75% 0,rgba(84,210,190,.13),transparent 36%),linear-gradient(150deg,#0b1216,#111c21 58%,#0b1318)} -.education-world button,.education-world input{font:inherit}.education-hero{display:grid;grid-template-columns:auto 1fr auto;gap:22px;align-items:start}.education-hero>button{background:transparent;border:0;color:#91aaa9;padding:10px}.education-hero span{font-size:11px;letter-spacing:.18em;color:#74d6c5}.education-hero h1{font-size:38px;margin:5px 0}.education-hero p{margin:0;color:#9db1b2}.education-hero aside{display:flex;flex-direction:column;align-items:flex-end;gap:5px}.education-hero aside b{color:#79d9c7}.education-hero aside small{color:#718588;max-width:260px;text-align:right} -.education-tabs{display:flex;gap:8px;margin:24px 0;border-bottom:1px solid #263a3d}.education-tabs button{border:0;background:transparent;color:#8da3a4;padding:12px 15px;border-bottom:2px solid transparent}.education-tabs button.active{color:#eafffb;border-color:#63d5c2} -.education-overview{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}.education-overview>article,.education-overview>section,.education-import,.education-action-layout>aside,.education-action-layout>main{background:#121f24;border:1px solid #26393d;border-radius:16px;padding:18px}.education-overview>article{display:flex;flex-direction:column;gap:8px}.education-overview>article strong{font-size:30px}.education-overview button,.education-editor-shell button,.education-action-layout button,.education-import button{border:1px solid #345155;background:#172b30;color:#dffbf6;border-radius:9px;padding:9px 12px}.education-overview>section{grid-column:span 2}.education-overview>section>button{width:100%;display:flex;justify-content:space-between;margin-top:8px;text-align:left}.education-overview small{color:#8ba0a2} -.education-editor-shell{display:grid;grid-template-columns:230px minmax(0,1fr);gap:14px;min-height:650px}.education-editor-shell>aside{display:flex;flex-direction:column;gap:7px;background:#0e191d;border:1px solid #26393d;border-radius:14px;padding:12px}.education-editor-shell>aside button{text-align:left;display:flex;flex-direction:column}.education-editor-shell button.active{border-color:#62d3c0;background:#1b3537}.education-editor-shell>main{min-width:0;background:#f7faf9;color:#172326;border-radius:14px;overflow:hidden}.education-editor-shell>main>header{display:flex;justify-content:space-between;gap:12px;padding:12px;background:#e8f0ee;border-bottom:1px solid #ccd9d6}.education-editor-shell>main>header input{flex:1;border:0;background:transparent;font-size:19px;font-weight:700;outline:0}.education-editor-shell>main>header>div{display:flex;gap:7px}.education-editor-shell button.danger{color:#ffc4bd;border-color:#734841;background:#33211f} -.education-action-layout{display:grid;grid-template-columns:250px 1fr;gap:14px}.education-action-layout aside{display:flex;flex-direction:column;gap:8px}.education-action-layout main{min-height:420px}.education-metrics{display:flex;gap:12px;margin:18px 0}.education-metrics b{font-size:26px;background:#0d191d;border-radius:12px;padding:14px 22px}.education-metrics small{font-size:11px;display:block;color:#91a6a7}.education-preview{margin-top:15px;padding:16px;border:1px solid #40726d;background:#102725;border-radius:12px}.education-preview p{color:#c9d7d5}.education-preview code{display:block;color:#78dbc9;margin:10px 0}.education-rule{margin-top:18px} -.education-import>header{display:flex;justify-content:space-between;align-items:center}.education-import dl{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}.education-import dl div{background:#0d181c;border-radius:10px;padding:12px}.education-import dt{color:#789092;font-size:12px}.education-import dd{margin:5px 0 0;overflow-wrap:anywhere}.education-import section article{display:flex;justify-content:space-between;align-items:center;padding:12px 0;border-top:1px solid #273b3e}.education-import section article div{display:flex;flex-direction:column}.education-import small{color:#89a0a1}.education-message{position:sticky;bottom:14px;background:#17302f;border:1px solid #4e8b83;color:#d8fff8;border-radius:12px;padding:12px 16px;margin:16px 0 0} +.education-world{min-height:100%;padding:28px;color:var(--content-primary);background:radial-gradient(circle at 75% 0,color-mix(in srgb,var(--primitive-cool-glow) 13%,transparent),transparent 36%),linear-gradient(150deg,var(--surface-depth),var(--surface-horizon) 58%,var(--surface-depth))} +.education-world button,.education-world input{font:inherit}.education-hero{display:grid;grid-template-columns:auto 1fr auto;gap:22px;align-items:start}.education-hero>button{background:transparent;border:0;color:var(--content-secondary);padding:10px}.education-hero span{font-size:11px;letter-spacing:.18em;color:var(--accent-light)}.education-hero h1{font-size:38px;margin:5px 0}.education-hero p{margin:0;color:var(--content-secondary)}.education-hero aside{display:flex;flex-direction:column;align-items:flex-end;gap:5px}.education-hero aside b{color:var(--state-ready)}.education-hero aside small{color:var(--content-muted);max-width:260px;text-align:right} +.education-tabs{display:flex;gap:8px;margin:24px 0;border-bottom:1px solid var(--panel-edge)}.education-tabs button{border:0;background:transparent;color:var(--content-secondary);padding:12px 15px;border-bottom:2px solid transparent}.education-tabs button.active{color:var(--content-primary);border-color:var(--accent-light)} +.education-overview{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}.education-overview>article,.education-overview>section,.education-import,.education-action-layout>aside,.education-action-layout>main{background:var(--panel-bg);border:1px solid var(--panel-edge);border-radius:16px;padding:18px}.education-overview>article{display:flex;flex-direction:column;gap:8px}.education-overview>article strong{font-size:30px}.education-overview button,.education-editor-shell button,.education-action-layout button,.education-import button{border:1px solid var(--button-secondary-edge);background:var(--button-secondary-bg);color:var(--button-secondary-text);border-radius:9px;padding:9px 12px}.education-overview>section{grid-column:span 2}.education-overview>section>button{width:100%;display:flex;justify-content:space-between;margin-top:8px;text-align:left}.education-overview small{color:var(--content-muted)} +.education-editor-shell{display:grid;grid-template-columns:230px minmax(0,1fr);gap:14px;min-height:650px}.education-editor-shell>aside{display:flex;flex-direction:column;gap:7px;background:var(--panel-bg);border:1px solid var(--panel-edge);border-radius:14px;padding:12px}.education-editor-shell>aside button{text-align:left;display:flex;flex-direction:column}.education-editor-shell button.active{border-color:var(--accent-light);background:color-mix(in srgb,var(--accent-light) 16%,var(--panel-bg))}.education-editor-shell>main{min-width:0;background:#f7faf9;color:#172326;border-radius:14px;overflow:hidden}.education-editor-shell>main>header{display:flex;justify-content:space-between;gap:12px;padding:12px;background:#e8f0ee;border-bottom:1px solid #ccd9d6}.education-editor-shell>main>header input{flex:1;border:0;background:transparent;font-size:19px;font-weight:700;outline:0}.education-editor-shell>main>header>div{display:flex;gap:7px}.education-editor-shell button.danger{color:var(--state-danger);border-color:color-mix(in srgb,var(--state-danger) 45%,var(--panel-edge));background:color-mix(in srgb,var(--state-danger) 12%,var(--panel-bg))} +.education-action-layout{display:grid;grid-template-columns:250px 1fr;gap:14px}.education-action-layout aside{display:flex;flex-direction:column;gap:8px}.education-action-layout main{min-height:420px}.education-metrics{display:flex;gap:12px;margin:18px 0}.education-metrics b{font-size:26px;background:var(--panel-bg);border-radius:12px;padding:14px 22px}.education-metrics small{font-size:11px;display:block;color:var(--content-muted)}.education-preview{margin-top:15px;padding:16px;border:1px solid var(--panel-edge);background:var(--panel-bg);border-radius:12px}.education-preview p{color:var(--content-secondary)}.education-preview code{display:block;color:var(--accent-light);margin:10px 0}.education-rule{margin-top:18px} +.education-import>header{display:flex;justify-content:space-between;align-items:center}.education-import dl{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}.education-import dl div{background:var(--panel-bg);border-radius:10px;padding:12px}.education-import dt{color:var(--content-muted);font-size:12px}.education-import dd{margin:5px 0 0;overflow-wrap:anywhere}.education-import section article{display:flex;justify-content:space-between;align-items:center;padding:12px 0;border-top:1px solid var(--panel-edge)}.education-import section article div{display:flex;flex-direction:column}.education-import small{color:var(--content-muted)}.education-message{position:sticky;bottom:14px;background:var(--panel-bg);border:1px solid var(--panel-edge);color:var(--content-primary);border-radius:12px;padding:12px 16px;margin:16px 0 0} @media(max-width:900px){.education-overview{grid-template-columns:repeat(2,1fr)}.education-editor-shell,.education-action-layout{grid-template-columns:1fr}.education-editor-shell>aside{max-height:180px;overflow:auto}.education-hero{grid-template-columns:1fr}.education-hero>button{justify-self:start}.education-import dl{grid-template-columns:1fr}} diff --git a/product-source/hololake-native-desktop/src/modules/qoder-surface/StarlakeSurface.tsx b/product-source/hololake-native-desktop/src/modules/qoder-surface/StarlakeSurface.tsx new file mode 100644 index 000000000..0aade0918 --- /dev/null +++ b/product-source/hololake-native-desktop/src/modules/qoder-surface/StarlakeSurface.tsx @@ -0,0 +1,144 @@ +import { useEffect, useMemo, useRef, useState, type CSSProperties } from 'react' +import './starlake-surface.css' + +export type DomainId = 'BRANCH_DOMAIN' | 'ZERO_SENSE_DOMAIN' | 'ZERO_DOMAIN' | 'MAIN_DOMAIN' | 'FIFTH_DOMAIN' +export type Phase = 'dawn' | 'day' | 'dusk' | 'night' + +interface StarlakeSurfaceProps { + awake?: boolean + phase?: Phase + weather?: string + authenticated?: boolean + onDomain: (domain: DomainId) => void + onOpenEra: () => void + onEnterChannel: () => void +} + +const EPOCH_MS = new Date('2025-04-26T00:00:00+08:00').getTime() +const WEEK = ['日', '一', '二', '三', '四', '五', '六'] +const PHASE_WORD: Record = { dawn: '晨', day: '午', dusk: '暮', night: '夜' } + +const DOMAINS = [ + { id: 'BRANCH_DOMAIN' as const, name: '分域', stage: 1, stageName: '聚光尘', hi: '#b9f2dd', lo: '#2c5a4a', glow: 'rgba(150,230,200,.5)', glowSoft: 'rgba(150,230,200,.18)', y: -34 }, + { id: 'ZERO_SENSE_DOMAIN' as const, name: '零感域', stage: 2, stageName: '凝星核', hi: '#dcc4ff', lo: '#48326a', glow: 'rgba(206,178,246,.5)', glowSoft: 'rgba(206,178,246,.18)', y: -56 }, + { id: 'ZERO_DOMAIN' as const, name: '零域', stage: 3, stageName: '初生环', hi: '#ffcf9e', lo: '#6e4630', glow: 'rgba(255,200,140,.5)', glowSoft: 'rgba(255,200,140,.18)', y: -40 }, + { id: 'MAIN_DOMAIN' as const, name: '主域', stage: 4, stageName: '行星态', hi: '#c9d6ff', lo: '#33406e', glow: 'rgba(168,190,255,.52)', glowSoft: 'rgba(168,190,255,.18)', y: -66 }, + { id: 'FIFTH_DOMAIN' as const, name: '第五域', stage: 5, stageName: '主星态', hi: '#fdeec2', lo: '#6b5626', glow: 'rgba(250,226,150,.56)', glowSoft: 'rgba(250,226,150,.2)', y: -48 }, +] + +function seeded(index: number) { + const value = Math.sin(index * 9283.17 + 17.73) * 43758.5453 + return value - Math.floor(value) +} + +function phaseOf(hour: number): Phase { + return hour < 5 ? 'night' : hour < 9 ? 'dawn' : hour < 16 ? 'day' : hour < 19 ? 'dusk' : 'night' +} + +export function StarlakeSurface({ awake = false, phase, weather = 'CLEAR', authenticated = false, onDomain, onOpenEra, onEnterChannel }: StarlakeSurfaceProps) { + const [now, setNow] = useState(() => new Date()) + const rootRef = useRef(null) + const [viewport, setViewport] = useState(() => ({ width: window.innerWidth, height: window.innerHeight })) + const livePhase = phase || phaseOf(now.getHours() + now.getMinutes() / 60) + const raining = ['RAIN', 'STORM'].includes(weather.toUpperCase()) + const dayNumber = Math.floor((now.getTime() - EPOCH_MS) / 86400000) + 1 + const dayIndex = ((dayNumber - 1) % DOMAINS.length + DOMAINS.length) % DOMAINS.length + + const stars = useMemo(() => Array.from({ length: 170 }, (_, index) => ({ + id: index, + size: .8 + seeded(index + 1) * 1.6, + left: seeded(index + 201) * 100, + top: seeded(index + 401) * 68, + opacity: .2 + seeded(index + 601) * .6, + duration: 2.5 + seeded(index + 801) * 5, + delay: -seeded(index + 1001) * 7, + warm: seeded(index + 1201) < .12, + })), []) + const lakeStars = useMemo(() => Array.from({ length: 140 }, (_, index) => ({ + id: index, + size: 1 + seeded(index + 1401) * 1.8, + left: seeded(index + 1601) * 100, + top: Math.pow(seeded(index + 1801), 1.6) * 92, + opacity: .22 + seeded(index + 2001) * .5, + duration: 2.4 + seeded(index + 2201) * 4, + delay: -seeded(index + 2401) * 6, + warm: seeded(index + 2601) < .18, + })), []) + const rain = useMemo(() => Array.from({ length: 90 }, (_, index) => ({ + id: index, + left: seeded(index + 2801) * 108, + duration: .9 + seeded(index + 3001) * .8, + delay: -seeded(index + 3201) * 2, + opacity: .3 + seeded(index + 3401) * .5, + })), []) + + useEffect(() => { + if (!awake) return + setNow(new Date()) + const timer = window.setInterval(() => setNow(new Date()), 125) + return () => window.clearInterval(timer) + }, [awake]) + + useEffect(() => { + const root = rootRef.current + if (!root) return + const observer = new ResizeObserver(([entry]) => setViewport({ width: entry.contentRect.width, height: entry.contentRect.height })) + observer.observe(root) + return () => observer.disconnect() + }, []) + + const pad = (value: number, length = 2) => String(value).padStart(length, '0') + // Qoder 验收稿按大画布设计;窗口版必须把整组“天体 + 水影 + 标签”一起缩放, + // 不能只挪坐标,否则第五域在常见 768px 高度下会把名称挤出视口。 + const naturalScale = Math.min(Math.max(Math.min(viewport.width / 1400, viewport.height / 1000), .64), 1.28) + const spacingScale = Math.max(.64, Math.min(1.28, (viewport.width - 72) / (5 * 180))) + const scale = Math.min(naturalScale, spacingScale) + const safeEdge = Math.max(46, 76 * scale) + const sideCenters = Array.from({ length: 5 }, (_, index) => safeEdge + (viewport.width - safeEdge * 2) * index / 4) + const sourceHour = now.getHours() + now.getMinutes() / 60 + now.getSeconds() / 3600 + const isDay = sourceHour >= 6 && sourceHour < 18 + const sourceProgress = isDay ? (sourceHour - 6) / 12 : ((sourceHour >= 18 ? sourceHour - 18 : sourceHour + 6) / 12) + const sourceX = 8 + sourceProgress * 84 + const sourceY = 46 - Math.sin(sourceProgress * Math.PI) * 26 + const sourceStyle = { left: `${sourceX}vw`, top: `${sourceY}vh`, '--src-mid': isDay ? '#ffe9a8' : '#dfe6fa', '--src-g1': isDay ? 'rgba(255,236,180,.7)' : 'rgba(214,226,255,.6)', '--src-g2': isDay ? 'rgba(255,220,140,.26)' : 'rgba(180,200,255,.22)', '--src-g3': isDay ? 'rgba(255,220,140,.12)' : 'rgba(180,200,255,.1)' } as CSSProperties + const glowStyle = { left: `${sourceX}vw`, top: `${sourceY}vh`, '--glow-tint': isDay ? 'rgba(255,236,180,.12)' : 'rgba(190,208,255,.09)' } as CSSProperties + const baseline = Math.min(viewport.height - 142 * scale, Math.max(viewport.height * .61, viewport.height * .665)) + const slots = [0, 1, 3, 4] + let sideCursor = 0 + + return
+
+} diff --git a/product-source/hololake-native-desktop/src/modules/qoder-surface/TraditionalSurface.tsx b/product-source/hololake-native-desktop/src/modules/qoder-surface/TraditionalSurface.tsx new file mode 100644 index 000000000..c515cd778 --- /dev/null +++ b/product-source/hololake-native-desktop/src/modules/qoder-surface/TraditionalSurface.tsx @@ -0,0 +1,102 @@ +import { useEffect, useRef } from 'react' +import './traditional-surface.css' + +/* Qoder 锁定验收稿的传统工作台结构。宿主只注入真实投影,不在视觉层制造广播或指标。 */ +export type FinishId = 'aurora' | 'nebula' | 'abyss' | 'jade' | 'cinnabar' | 'champagne' | 'porcelain' | 'snow' + +export const FINISHES: Array<{ id: FinishId; name: string }> = [ + { id: 'aurora', name: '曜夜' }, { id: 'nebula', name: '星辉' }, { id: 'abyss', name: '深海' }, { id: 'jade', name: '翡翠' }, + { id: 'cinnabar', name: '朱砂' }, { id: 'champagne', name: '香槟' }, { id: 'porcelain', name: '瓷光' }, { id: 'snow', name: '雪霁' }, +] + +const BROADCAST_COLOR: Record = { 分域: '#7ce8c8', 零感域: '#cfa8ff', 零域: '#ffbe85', 主域: '#a8bcff', 第五域: '#fdeec2' } +export interface TraditionalBroadcast { id: string; domain: string; message: string; time: string } +export interface TraditionalChannel { color: string; title: string; meta: string; tag: string; tone: string; count: number } +export interface TraditionalSystem { title: string; meta: string; tag: string; tone?: string } + +interface TraditionalSurfaceProps { + awake?: boolean + finish: FinishId + onFinish: (finish: FinishId) => void + onActivity?: () => void + onBack: () => void + onOpenKnowledge?: () => void + onOpenChannel?: () => void + onOpenEra?: () => void + onOpenSettings?: () => void + identityLabel?: string + version: string + dayNumber: number + duty: string + weatherLabel: string + broadcasts: TraditionalBroadcast[] + channels: TraditionalChannel[] + systems: TraditionalSystem[] + activityBars: number[] + activityCount: number +} + +export function TraditionalSurface({ awake = false, finish, onFinish, onActivity, onBack, onOpenKnowledge, onOpenChannel, onOpenEra, onOpenSettings, identityLabel = '光湖语言系统', version, dayNumber, duty, weatherLabel, broadcasts, channels, systems, activityBars, activityCount }: TraditionalSurfaceProps) { + const rootRef = useRef(null) + const clockRef = useRef(null) + + useEffect(() => { + const tick = () => { + const el = clockRef.current + if (!el) return + const now = new Date() + const pad = (value: number, length = 2) => String(value).padStart(length, '0') + el.textContent = `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}.${pad(now.getMilliseconds(), 3)}` + } + tick() + if (!awake) return + const timer = window.setInterval(tick, 125) + return () => window.clearInterval(timer) + }, [awake]) + + useEffect(() => { + const element = rootRef.current + if (!element) return + const layout = () => { + const { width, height } = element.getBoundingClientRect() + const vmin = Math.min(width, height) + element.style.setProperty('--gap', `${Math.round(Math.min(18, Math.max(10, vmin * .016)))}px`) + element.style.setProperty('--pad', `${Math.round(Math.min(26, Math.max(12, vmin * .02)))}px`) + const narrow = width < 880 + element.classList.toggle('stack', narrow) + if (!narrow) element.style.setProperty('--cols', `${Math.min(1.32, Math.max(1.08, width / height * .66)).toFixed(2)}fr 1fr`) + } + const observer = new ResizeObserver(layout) + observer.observe(element) + layout() + return () => observer.disconnect() + }, []) + + const pickFinish = (id: FinishId) => { onFinish(id); window.localStorage.setItem('hololake-finish', id) } + const maxBar = Math.max(1, ...activityBars) + + return
+