devagent-ignition 0.1.0__py3-none-any.whl
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.
- devagent_hmi.py +471 -0
- devagent_ignition-0.1.0.dist-info/METADATA +204 -0
- devagent_ignition-0.1.0.dist-info/RECORD +133 -0
- devagent_ignition-0.1.0.dist-info/WHEEL +4 -0
- devagent_ignition-0.1.0.dist-info/entry_points.txt +2 -0
- devagent_spatial/__init__.py +1 -0
- devagent_spatial/_resources/README.md +187 -0
- devagent_spatial/_resources/RELEASE_MANIFEST.json +312 -0
- devagent_spatial/_resources/SHA256SUMS.txt +270 -0
- devagent_spatial/_resources/SOURCE_PROVENANCE.json +186 -0
- devagent_spatial/_resources/assets/agent.js +102 -0
- devagent_spatial/_resources/assets/creator.css +247 -0
- devagent_spatial/_resources/assets/creator_2d.mjs +16 -0
- devagent_spatial/_resources/assets/creator_original_r9.mjs +58 -0
- devagent_spatial/_resources/assets/creator_original_v8.mjs +120 -0
- devagent_spatial/_resources/assets/creator_r9_diagnostics.mjs +53 -0
- devagent_spatial/_resources/assets/creator_scene.mjs +128 -0
- devagent_spatial/_resources/assets/creator_ui.mjs +60 -0
- devagent_spatial/_resources/assets/customer_documents.js +110 -0
- devagent_spatial/_resources/assets/equipment_controls.mjs +27 -0
- devagent_spatial/_resources/assets/facility2d.css +24 -0
- devagent_spatial/_resources/assets/facility2d_app.mjs +45 -0
- devagent_spatial/_resources/assets/facility2d_core.mjs +114 -0
- devagent_spatial/_resources/assets/facility2d_simulation.mjs +167 -0
- devagent_spatial/_resources/assets/facility2d_viewer.html +7 -0
- devagent_spatial/_resources/assets/fallback_scene.js +17 -0
- devagent_spatial/_resources/assets/flow_geometry.mjs +218 -0
- devagent_spatial/_resources/assets/harness.js +78 -0
- devagent_spatial/_resources/assets/live_design_review.js +129 -0
- devagent_spatial/_resources/assets/operations_ui.js +305 -0
- devagent_spatial/_resources/assets/operator_viewer.html +64 -0
- devagent_spatial/_resources/assets/project_package.js +52 -0
- devagent_spatial/_resources/assets/r9_transport.mjs +70 -0
- devagent_spatial/_resources/assets/runtime_feed.js +30 -0
- devagent_spatial/_resources/assets/studio.html +139 -0
- devagent_spatial/_resources/assets/style.css +191 -0
- devagent_spatial/_resources/assets/test_workspace.html +195 -0
- devagent_spatial/_resources/assets/three_scene.js +442 -0
- devagent_spatial/_resources/assets/unified_engineer.js +101 -0
- devagent_spatial/_resources/assets/v076_fat_ui.js +40 -0
- devagent_spatial/_resources/assets/v078_command_ui.js +44 -0
- devagent_spatial/_resources/assets/viewer.html +45 -0
- devagent_spatial/_resources/assets/viewer.js +112 -0
- devagent_spatial/_resources/design-system.json +130 -0
- devagent_spatial/_resources/examples/CV101-command-contract-PENDING.json +30 -0
- devagent_spatial/_resources/examples/cv101_guided.json +272 -0
- devagent_spatial/_resources/examples/make_examples.py +36 -0
- devagent_spatial/_resources/examples/single_floor.json +444 -0
- devagent_spatial/_resources/examples/v0771_training_wizard.json +11 -0
- devagent_spatial/_resources/examples/warehouse-3floor-standard-2d.json +708 -0
- devagent_spatial/_resources/examples/warehouse-operations-synthetic.json +1186 -0
- devagent_spatial/_resources/examples/warehouse-v07-lab-bindings-PENDING.json +372 -0
- devagent_spatial/_resources/examples/warehouse.json +708 -0
- devagent_spatial/_resources/examples/water.json +288 -0
- devagent_spatial/_resources/reference/r9-golden/REFERENCE_SHA256.json +13 -0
- devagent_spatial/_resources/reference/r9-golden/web/app.mjs +745 -0
- devagent_spatial/_resources/reference/r9-golden/web/index.html +213 -0
- devagent_spatial/_resources/reference/r9-golden/web/lab_panel.mjs +53 -0
- devagent_spatial/_resources/reference/r9-golden/web/model.mjs +367 -0
- devagent_spatial/_resources/reference/r9-golden/web/state_adapter.mjs +78 -0
- devagent_spatial/_resources/reference/r9-golden/web/styles.css +76 -0
- devagent_spatial/_resources/reference/r9-original/README_R9.md +27 -0
- devagent_spatial/_resources/reference/r9-original/SHA256SUMS.txt +63 -0
- devagent_spatial/_resources/reference/r9-original/SNAPSHOT_SHA256SUMS.txt +16 -0
- devagent_spatial/_resources/reference/r9-original/flow_routes.json +527 -0
- devagent_spatial/_resources/reference/r9-original/flow_sim.py +117 -0
- devagent_spatial/_resources/reference/r9-original/lab_control.py +73 -0
- devagent_spatial/_resources/reference/r9-original/web/app.mjs +745 -0
- devagent_spatial/_resources/reference/r9-original/web/index.html +213 -0
- devagent_spatial/_resources/reference/r9-original/web/lab_panel.mjs +53 -0
- devagent_spatial/_resources/reference/r9-original/web/model.mjs +367 -0
- devagent_spatial/_resources/reference/r9-original/web/state_adapter.mjs +78 -0
- devagent_spatial/_resources/reference/r9-original/web/styles.css +76 -0
- devagent_spatial/_resources/reference/r9-original/web/vendor/LICENSE-three.txt +21 -0
- devagent_spatial/_resources/reference/r9-original/web/vendor/SHA256SUMS.txt +4 -0
- devagent_spatial/_resources/reference/r9-original/web/vendor/addons/controls/OrbitControls.js +1860 -0
- devagent_spatial/_resources/reference/r9-original/web/vendor/three.core.js +58773 -0
- devagent_spatial/_resources/reference/r9-original/web/vendor/three.module.js +18251 -0
- devagent_spatial/_resources/reference/v8-original/README.md +36 -0
- devagent_spatial/_resources/reference/v8-original/SHA256SUMS.txt +12 -0
- devagent_spatial/_resources/reference/v8-original/model.py +124 -0
- devagent_spatial/_resources/reference/v8-original/run_demo.sh +4 -0
- devagent_spatial/_resources/reference/v8-original/server.py +100 -0
- devagent_spatial/_resources/reference/v8-original/tests/browser_smoke.py +50 -0
- devagent_spatial/_resources/reference/v8-original/tests/test_v8.py +144 -0
- devagent_spatial/_resources/reference/v8-original/topology.json +24 -0
- devagent_spatial/_resources/reference/v8-original/web/app.js +114 -0
- devagent_spatial/_resources/reference/v8-original/web/index.html +22 -0
- devagent_spatial/_resources/reference/v8-original/web/simulator.html +1 -0
- devagent_spatial/_resources/reference/v8-original/web/simulator.js +6 -0
- devagent_spatial/_resources/reference/v8-original/web/style.css +16 -0
- devagent_spatial/_resources/sample_customer_inputs/Plant_Equipment_Register.csv +4 -0
- devagent_spatial/_resources/sample_customer_inputs/Plant_Flow_Requirements.txt +5 -0
- devagent_spatial/_resources/sample_customer_inputs/Raw_PLC_Tag_Export.csv +4 -0
- devagent_spatial/_resources/templates/warehouse_connections.csv +12 -0
- devagent_spatial/_resources/templates/warehouse_equipment.csv +21 -0
- devagent_spatial/_resources/templates/warehouse_signals.csv +34 -0
- devagent_spatial/_resources/templates/water_connections.csv +7 -0
- devagent_spatial/_resources/templates/water_equipment.csv +10 -0
- devagent_spatial/_resources/templates/water_signals.csv +12 -0
- devagent_spatial/agent_harness.py +299 -0
- devagent_spatial/agent_runtime.py +314 -0
- devagent_spatial/contract_opc_fat.py +216 -0
- devagent_spatial/contract_opc_source.py +265 -0
- devagent_spatial/control_intents.py +38 -0
- devagent_spatial/customer_intake.py +235 -0
- devagent_spatial/engineering_expertise.py +114 -0
- devagent_spatial/generator.py +201 -0
- devagent_spatial/ignition_native.py +234 -0
- devagent_spatial/ignition_project.py +144 -0
- devagent_spatial/live_lab_binding.py +128 -0
- devagent_spatial/model.py +297 -0
- devagent_spatial/native_reference.py +69 -0
- devagent_spatial/opc_snapshot.py +87 -0
- devagent_spatial/operations.py +284 -0
- devagent_spatial/operations_capture.py +47 -0
- devagent_spatial/operations_lab.py +64 -0
- devagent_spatial/original_r9.py +169 -0
- devagent_spatial/original_v8.py +81 -0
- devagent_spatial/preflight.py +140 -0
- devagent_spatial/preview_simulation.py +189 -0
- devagent_spatial/project_package.py +101 -0
- devagent_spatial/qualification.py +152 -0
- devagent_spatial/strict_json.py +29 -0
- devagent_spatial/studio.py +894 -0
- devagent_spatial/studio_workflow.py +277 -0
- devagent_spatial/test_reporting.py +87 -0
- devagent_spatial/v076_opc_fat.py +180 -0
- devagent_spatial/v078_commands.py +277 -0
- devagent_spatial/v078_native_commands.py +161 -0
- devagent_spatial/v07_fat.py +110 -0
- devagent_spatial/v07_native.py +318 -0
- devagent_spatial/v083_native.py +349 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/* V0.7.9.2 read-only project archive import. Never bypasses AI/harness/production gates. */
|
|
2
|
+
(()=>{'use strict';
|
|
3
|
+
const $=id=>document.getElementById(id);
|
|
4
|
+
const input=$('project-package-file'),result=$('project-package-result'),review=$('project-package-review');
|
|
5
|
+
const choice=$('project-package-choice'),apply=$('project-package-apply');
|
|
6
|
+
if(!input||!result||!review||!choice||!apply)return;
|
|
7
|
+
let options=null,seq=0;
|
|
8
|
+
async function inspect(file){
|
|
9
|
+
const serial=++seq;options=null;review.hidden=true;
|
|
10
|
+
if(!file){result.textContent='No package selected';return;}
|
|
11
|
+
if(!/\.zip$/i.test(file.name)||file.size>8_000_000||file.size<20){result.textContent='HOLD: Select a ZIP under 8 MB.';return;}
|
|
12
|
+
result.textContent='Inspecting input files only. No AI call…';
|
|
13
|
+
try{
|
|
14
|
+
const response=await fetch('/api/customer-package/inspect',{method:'POST',
|
|
15
|
+
headers:{'Content-Type':'application/octet-stream','X-DevAgent-Request':'customer-project-package-v1',
|
|
16
|
+
'X-DevAgent-Filename':encodeURIComponent(file.name)},body:file});
|
|
17
|
+
const data=await response.json();if(serial!==seq)return;
|
|
18
|
+
if(!response.ok||data.status!=='REVIEW_REQUIRED'||!Array.isArray(data.options)){
|
|
19
|
+
result.textContent='HOLD: '+(data.reason||'UNKNOWN_PACKAGE_ERROR');return;
|
|
20
|
+
}
|
|
21
|
+
options=data.options;choice.replaceChildren();
|
|
22
|
+
for(const p of options){const e=document.createElement('option');e.value=p.id;
|
|
23
|
+
e.textContent=p.label+' · '+p.equipment+' equipment · '+p.signals+' signals';choice.append(e);}
|
|
24
|
+
review.hidden=false;showChoice();
|
|
25
|
+
}catch(e){if(serial===seq)result.textContent='HOLD: Could not inspect the package. No data changed.';}
|
|
26
|
+
}
|
|
27
|
+
function showChoice(){if(!options)return;const p=options.find(x=>x.id===choice.value);if(!p)return;
|
|
28
|
+
result.textContent=`${p.label}\n${p.equipment} equipment · ${p.links} connections · ${p.signals} signals · ${p.requirements} requirements\n`+
|
|
29
|
+
(p.training?'Training-only OPC mappings — NOT VERIFIED.':'Source mappings require independent verification.')+
|
|
30
|
+
'\nReview and confirm before importing. Nothing applied yet.';
|
|
31
|
+
}
|
|
32
|
+
input.addEventListener('change',()=>inspect(input.files?.[0]));
|
|
33
|
+
document.addEventListener('devagent:package-selected',e=>inspect(e.detail?.file));
|
|
34
|
+
choice.addEventListener('change',showChoice);
|
|
35
|
+
document.addEventListener('devagent:project-reset',()=>{
|
|
36
|
+
seq++;options=null;input.value='';choice.replaceChildren();review.hidden=true;result.textContent='No package selected';
|
|
37
|
+
});
|
|
38
|
+
apply.addEventListener('click',()=>{
|
|
39
|
+
if(!options)return;
|
|
40
|
+
const p=options.find(x=>x.id===choice.value);if(!p)return;
|
|
41
|
+
const fields=['name','industry','description','equipment_csv','connections_csv','signals_csv','requirements'];
|
|
42
|
+
const existing=fields.filter(k=>$(k)&&$(k).value.trim());
|
|
43
|
+
if(existing.length&&!confirm('Replace existing Creator inputs ('+existing.join(', ')+') with '+p.label+'?\nThe 2D/3D design selection will be preserved.'))return;
|
|
44
|
+
// A reviewed import changes customer inputs only; the existing AI receipt must be revoked by input change events.
|
|
45
|
+
for(const k of fields){if(!$(k))continue;const value=p.wizard[k]||'';
|
|
46
|
+
if(k==='industry'&&value==='Unspecified Industry')continue;
|
|
47
|
+
$(k).value=value;$(k).dispatchEvent(new Event('input',{bubbles:true}));}
|
|
48
|
+
result.textContent='Inputs loaded: '+p.equipment+' equipment / '+p.signals+' signals.\nNext: Review the four steps, then run AI Engineer → Verify. Production HOLD.';
|
|
49
|
+
review.hidden=true;
|
|
50
|
+
input.value='';
|
|
51
|
+
});
|
|
52
|
+
})();
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DevAgent R9 Golden Conveyor Surface Pack (viewer-only, NO process state).
|
|
3
|
+
* Derived carefully from the uploaded reference `web/app.mjs` lines 74-105,
|
|
4
|
+
* 118-135. `pathGeom` and `sideCurve` follow the reference centerline,
|
|
5
|
+
* horizontal-normal, true arc-length sampling and rail algorithms.
|
|
6
|
+
* Adaptation: inject the exact local Three.js module and bound tessellation.
|
|
7
|
+
* Never claims mechanical clearance, vendor geometry or physical mapping.
|
|
8
|
+
*/
|
|
9
|
+
export function pathGeom(THREE, curve, width=.85, shift=0, stepCount=null){
|
|
10
|
+
if(!Number.isFinite(width)||width<=0||width>100)throw Error('R9_INVALID_BELT_WIDTH');
|
|
11
|
+
const length=curve.getLength(),n=Math.min(1800,Math.max(15,stepCount||Math.ceil(length*9)));
|
|
12
|
+
if(!Number.isFinite(length)||length<=0||length>3000)throw Error('R9_INVALID_PATH_LENGTH');
|
|
13
|
+
const vs=[],ns=[],uv=[],idx=[];
|
|
14
|
+
for(let i=0;i<=n;i++){
|
|
15
|
+
const t=i/n,p=curve.getPointAt(t),tan=curve.getTangentAt(t);
|
|
16
|
+
const normal=new THREE.Vector3(-tan.z,0,tan.x);
|
|
17
|
+
if(normal.lengthSq()<1e-12)throw Error('R9_VERTICAL_PATH_REQUIRES_APPROVED_LATERAL_FRAME');
|
|
18
|
+
normal.normalize();
|
|
19
|
+
for(const side of [-1,1]){
|
|
20
|
+
const v=p.clone().addScaledVector(normal,side*width*.5);
|
|
21
|
+
vs.push(v.x,v.y+shift,v.z);ns.push(0,1,0);uv.push(t*length,side===-1?0:1);
|
|
22
|
+
}
|
|
23
|
+
if(i<n){const j=2*i;idx.push(j,j+1,j+2,j+1,j+3,j+2)}
|
|
24
|
+
}
|
|
25
|
+
const geom=new THREE.BufferGeometry();
|
|
26
|
+
geom.setAttribute('position',new THREE.Float32BufferAttribute(vs,3));
|
|
27
|
+
geom.setAttribute('normal',new THREE.Float32BufferAttribute(ns,3));
|
|
28
|
+
geom.setAttribute('uv',new THREE.Float32BufferAttribute(uv,2));
|
|
29
|
+
geom.setIndex(idx);geom.computeVertexNormals();return geom;
|
|
30
|
+
}
|
|
31
|
+
export function sideCurve(THREE,curve,side,width,raise=0){
|
|
32
|
+
const out=[],n=Math.min(1200,Math.max(16,Math.ceil(curve.getLength()*6)));
|
|
33
|
+
for(let i=0;i<=n;i++){
|
|
34
|
+
const t=i/n,p=curve.getPointAt(t),tan=curve.getTangentAt(t);
|
|
35
|
+
const norm=new THREE.Vector3(-tan.z,0,tan.x);
|
|
36
|
+
if(norm.lengthSq()<1e-12)throw Error('R9_VERTICAL_PATH_REQUIRES_APPROVED_LATERAL_FRAME');
|
|
37
|
+
norm.normalize();out.push(p.addScaledVector(norm,side*width).add(new THREE.Vector3(0,raise,0)));
|
|
38
|
+
}
|
|
39
|
+
return new THREE.CatmullRomCurve3(out,false,'centripetal');
|
|
40
|
+
}
|
|
41
|
+
export function buildR9Transport(THREE,parent,curve,options){
|
|
42
|
+
const {width=.9,materials,conceptual=true,rollers=true}=options;
|
|
43
|
+
if(!materials?.frame||!materials?.belt||!materials?.rail||!materials?.roller)throw Error('R9_MATERIALS_MISSING');
|
|
44
|
+
const group=new THREE.Group();
|
|
45
|
+
group.userData.renderSystem='R9_GOLDEN_CENTERLINE_RIBBON';
|
|
46
|
+
group.userData.geometry_status=conceptual?'CONCEPTUAL_CONNECTION_NEEDS_APPROVAL':'REFERENCE_GEOMETRY_NOT_AS_BUILT';
|
|
47
|
+
const underside=new THREE.Mesh(pathGeom(THREE,curve,width*1.17,-.23),materials.frame);
|
|
48
|
+
underside.castShadow=true;underside.receiveShadow=true;group.add(underside);
|
|
49
|
+
const deck=new THREE.Mesh(pathGeom(THREE,curve,width*.94,.025),materials.belt);
|
|
50
|
+
deck.castShadow=true;deck.receiveShadow=true;group.add(deck);
|
|
51
|
+
for(const side of [-1,1]){
|
|
52
|
+
const edge=sideCurve(THREE,curve,side,width*.55,.14);
|
|
53
|
+
const tube=new THREE.Mesh(new THREE.TubeGeometry(edge,
|
|
54
|
+
Math.min(1200,Math.max(12,Math.floor(curve.getLength()*5))),.042,7,false),materials.rail);
|
|
55
|
+
tube.castShadow=true;group.add(tube);
|
|
56
|
+
}
|
|
57
|
+
if(rollers){
|
|
58
|
+
const n=Math.min(72,Math.floor(curve.getLength()/.8));
|
|
59
|
+
const rollerGeo=new THREE.CylinderGeometry(.048,.048,width*.78,8);
|
|
60
|
+
const up=new THREE.Vector3(0,1,0);
|
|
61
|
+
for(let i=1;i<n;i++){
|
|
62
|
+
const t=i/n,p=curve.getPointAt(t),tan=curve.getTangentAt(t),across=new THREE.Vector3(-tan.z,0,tan.x);
|
|
63
|
+
if(across.lengthSq()<1e-12)continue;
|
|
64
|
+
across.normalize();const roller=new THREE.Mesh(rollerGeo,materials.roller);
|
|
65
|
+
roller.position.copy(p);roller.position.y+=.057;
|
|
66
|
+
roller.quaternion.setFromUnitVectors(up,across);group.add(roller);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
parent.add(group);return group;
|
|
70
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/* Project-scoped read-only Studio lab adapter, no user test controls on Operator UI.
|
|
2
|
+
NEVER claims native Ignition, physical PLC, production source or write authority. */
|
|
3
|
+
export function startLabFeed({operations,projectId,refreshMs=1000,onReading=()=>{}}) {
|
|
4
|
+
const valid=/^[a-z0-9-]{1,100}$/.test(projectId);
|
|
5
|
+
if(!valid)throw Error('INVALID_PROJECT_ID');
|
|
6
|
+
let disposed=false,inflight=false,timer=null;
|
|
7
|
+
const endpoint=`/api/live-lab/${encodeURIComponent(projectId)}/readings`;
|
|
8
|
+
async function tick(){
|
|
9
|
+
if(disposed||inflight)return;
|
|
10
|
+
if(document.visibilityState==='hidden')return;
|
|
11
|
+
inflight=true;
|
|
12
|
+
const controller=new AbortController();const timeout=setTimeout(()=>controller.abort(),20000);
|
|
13
|
+
try{
|
|
14
|
+
const response=await fetch(endpoint,{cache:'no-store',credentials:'same-origin',signal:controller.signal});
|
|
15
|
+
const result=await response.json();
|
|
16
|
+
if(disposed)return;
|
|
17
|
+
if(response.ok && result.status==='PASS_STUDIO_LAB_DISPLAY_ONLY')operations.applyLabReading(result);
|
|
18
|
+
else if(response.ok && result.status==='PASS_SYNTHETIC_PREVIEW_ONLY')operations.applySyntheticReading(result);
|
|
19
|
+
else operations.sourceUnavailable();
|
|
20
|
+
onReading(response.ok?result:null);
|
|
21
|
+
}catch(_err){if(!disposed){operations.sourceUnavailable();onReading(null);}}
|
|
22
|
+
finally{clearTimeout(timeout);inflight=false;}
|
|
23
|
+
}
|
|
24
|
+
// Fail closed immediately; Studio is never implicitly connected or trusted.
|
|
25
|
+
operations.sourceUnavailable();tick();
|
|
26
|
+
timer=setInterval(tick,refreshMs);
|
|
27
|
+
const onVisible=()=>{if(document.visibilityState!=='hidden')tick();};
|
|
28
|
+
document.addEventListener('visibilitychange',onVisible);
|
|
29
|
+
return ()=>{disposed=true;clearInterval(timer);document.removeEventListener('visibilitychange',onVisible);operations.sourceUnavailable();};
|
|
30
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="color-scheme" content="light"><title>DevAgent — Spatial HMI Creator</title><style>
|
|
2
|
+
:root{color-scheme:dark;--bg:#081622;--panel:#0e2638;--card:#123248;--border:#30566d;--text:#e9f4fc;--muted:#9bb5c6;--accent:#64c4dc;--warm:#f0c681;--ok:#4ecbaa}*{box-sizing:border-box}body{background:var(--bg);color:var(--text);font-family:Inter,system-ui,-apple-system,'Segoe UI',sans-serif;font-size:14px;margin:0}header{border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;padding:22px 28px;gap:14px}h1{font-size:22px;margin:5px 0 0}h2{font-size:18px;margin:0 0 10px}p{color:var(--muted);line-height:1.6}.eyebrow{font-size:10px;font-weight:800;color:var(--accent);letter-spacing:.12em}.pill{border:1px solid #58788b;color:var(--accent);font-size:11px;border-radius:20px;padding:8px 10px}.wrap{max-width:1220px;margin:0 auto;padding:22px;display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:16px}.steps{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:16px}.step{background:#11293a;border:1px solid var(--border);border-radius:5px;padding:10px 14px;color:var(--muted)}.step.active{background:#205b72;color:#f5ffff;border-color:#53a7bc}.panel{background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:22px;margin-bottom:14px}.panel:not(.active-panel){display:none}.grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}label{display:block;font-size:11px;letter-spacing:.03em;font-weight:700;color:#b7d6e4;margin:0 0 7px}input,textarea,select{width:100%;color:var(--text);background:#0a1c2a;border:1px solid #42657b;border-radius:6px;padding:12px 13px;font:inherit;line-height:1.35}textarea{min-height:155px;resize:vertical;font-family:ui-monospace,monospace;font-size:12px}input:focus,textarea:focus,select:focus,button:focus-visible{outline:2px solid var(--accent);outline-offset:2px}small.tip{display:block;color:var(--muted);font-size:11px;line-height:1.5;margin:6px 0 14px}button{font:inherit;border:1px solid #48819b;border-radius:6px;background:#183f57;padding:11px 15px;color:#e9f7ff;cursor:pointer;min-height:42px}button.primary{background:#207f99;border-color:#329cb9;font-weight:700}button:hover{filter:brightness(1.13)}button:disabled{opacity:.55;cursor:not-allowed}.actions{display:flex;justify-content:space-between;gap:12px;margin:18px 0;flex-wrap:wrap}.action-left,.action-right{display:flex;gap:8px;align-items:center}.aside{position:sticky;top:14px;align-self:start}.aside .panel{display:block}.row{display:flex;justify-content:space-between;border-bottom:1px solid #25475c;padding:12px 0;gap:8px}.row span{color:var(--muted);font-size:12px}.row b{text-align:right;font-size:12px}.status{white-space:pre-wrap;overflow-wrap:anywhere;padding:12px;border:1px solid #476277;background:#0b1b2b;border-radius:6px;font-size:12px;line-height:1.6;max-height:300px;overflow:auto}.status.hold{border-color:#97704d;color:#f0cca6}.status.pass{border-color:#377b7a;color:#94e0d3}.notice{background:#102938;border-left:3px solid var(--accent);padding:12px;line-height:1.55;font-size:12px;color:#a5c6d6}.success{padding:14px;border:1px solid #377b7a;background:#112f35;border-radius:6px;margin-top:12px}.success a{color:#9be4f3;font-weight:700}.compact{font-size:11px}.file-row{display:flex;align-items:center;gap:8px;margin-bottom:12px;flex-wrap:wrap}.file-row input{width:auto;max-width:100%;font-size:11px}.preset-row{display:flex;gap:8px;flex-wrap:wrap}.fields{margin-top:20px}.hidden{display:none!important}@media(max-width:880px){.wrap{grid-template-columns:1fr}.aside{position:static}.grid{grid-template-columns:1fr}header{padding:18px}.wrap{padding:14px}}
|
|
3
|
+
|
|
4
|
+
.agent-panel{background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:18px;margin-bottom:16px}.agent-top{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.agent-top strong{display:block;margin-top:4px}.agent-settings{margin-top:14px;border-top:1px solid var(--border);padding-top:14px}.agent-panel textarea{max-height:130px;min-height:66px}.agent-panel .status{margin-top:12px;max-height:250px}.agent-panel .fields{margin-top:12px}#ai-approval{margin-top:10px}#ai-connection-status{color:var(--muted)}
|
|
5
|
+
</style><!-- ENGINE 0.5 original creator contract provenance; current UI is v0.7.5 --><link rel="stylesheet" href="/assets/creator.css"></head><body>
|
|
6
|
+
<header class="app-header"><div class="brand-lockup"><div class="brand-mark" aria-hidden="true"><span>D</span><span>A</span></div><div class="brand-title"><div class="eyebrow">DEVAGENT <span class="breadcrumb-divider">/</span> ENGINEERING STUDIO</div><h1>HMI Creator <span class="release-pill">V0.8.2 · 3D PREVIEW</span></h1></div></div><div class="header-right"><div class="header-context">CREATOR <b> / New project</b></div><button type="button" id="new-project" class="new-project-button">New Project</button><button type="button" id="header-ai-status" class="header-ai-status" aria-controls="byom-onboarding" aria-expanded="false" aria-label="Open AI connection settings" title="Change AI provider or model" hidden><span class="header-ai-dot" aria-hidden="true"></span><span id="header-ai-label">Connected</span></button><div class="pill"><span class="lab-dot" aria-hidden="true"></span>LAB MODE <span class="lab-secondary">· READ ONLY · NO PLC WRITES</span></div></div></header>
|
|
7
|
+
<section id="byom-onboarding" class="byom-onboarding" aria-label="Step zero: connect your AI provider">
|
|
8
|
+
<div class="byom-topline"><span class="byom-identity"><span class="byom-spark" aria-hidden="true">✧</span> DEVAGENT AI ENGINEERING AGENT</span><span id="byom-phase" class="byom-phase">STEP 00 · CONNECTION REQUIRED</span></div>
|
|
9
|
+
<div class="byom-head"><div><span class="byom-kicker">START HERE / YOUR AI, OUR ENGINEERING RULES</span><h2>Connect AI Model. <span>Then build your factory.</span></h2><p>Choose a model you trust. Next, enter only the plant data and requirements you have. DevAgent proposes solutions, independently validates them, and prepares a professional HMI and lab test plan.</p></div><div class="byom-progress" aria-label="Guided workflow"><span class="byom-current">01 <b>Connect AI</b></span><span>02 <b>Your inputs</b></span><span>03 <b>AI + engine</b></span><span>04 <b>Generate & test</b></span></div></div>
|
|
10
|
+
<div class="connect-card" aria-label="AI provider connection box">
|
|
11
|
+
<div class="connect-card-head"><div><span class="byom-kicker">01 / CONNECT YOUR MODEL</span><h2>AI Connection <span>· Your model</span></h2><p>Choose a provider and model, then click <b>Test Connection</b>. You can change it anytime.</p></div><span id="connection-indicator" class="connection-indicator" role="status" aria-live="polite">Not connected</span></div>
|
|
12
|
+
<div id="byom-form-mount" class="byom-form-mount"></div>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="byom-bottom"><span>🔒 Provider/model credentials remain in this browser session. Project data is sent to the chosen provider only when you request AI analysis. Connection testing is not an engineering or production approval.</span><button id="byom-change" type="button" hidden>Change AI provider</button></div>
|
|
15
|
+
</section>
|
|
16
|
+
<div class="wrap" id="creator-ui-shell" hidden><section>
|
|
17
|
+
<div class="hero"><div class="hero-copy"><div class="eyebrow"><span class="eyebrow-dot"></span> DESIGN STUDIO <span class="eyebrow-slash">/</span> FROM DATA TO HMI</div><h2>Design your factory.<br><span>See it come to life.</span></h2><p>Transform your equipment list into a professional HMI concept and a test-ready Digital Twin. Start with what you have — no PLC connection required.</p><div class="quick-pills"><span>Equipment-aware</span><span>4 simple steps</span><span>Evidence-first FAT</span></div></div><div class="hero-deco" aria-hidden="true"><div class="hero-orbit orbit-1"></div><div class="hero-orbit orbit-2"></div><div class="hero-line"></div><div class="hero-node node-a"></div><div class="hero-node node-b"></div><div class="hero-node node-c"></div></div></div>
|
|
18
|
+
<section class="creator-start" aria-label="Creator actions"><div class="creator-start-head"><div><div class="eyebrow">CREATOR</div><h2>Start a project</h2><p>Demo simulation is isolated and cannot write to PLC or OPC UA endpoints.</p></div><button type="button" id="clear-existing">Clear Existing</button></div><div class="creator-start-cards"><button type="button" id="demo-original-v8" class="creator-start-card original-v8-card" aria-pressed="false"><strong>2D Flow — Original V8</strong><small>Distribution operations</small></button><button type="button" id="demo-original-r9" class="creator-start-card original-r9-card" aria-pressed="false"><strong>3D Flow — Original R9 Four Spirals</strong><small>Three-floor spatial operations</small></button><button type="button" id="new-project-card" class="creator-start-card blank-project-card"><strong>New Project</strong><small>Begin with empty inputs</small></button></div></section>
|
|
19
|
+
<section class="unified-engineer" aria-label="AI and Engineering Engine unified workflow">
|
|
20
|
+
<div class="unified-kicker">AI ENGINEER</div>
|
|
21
|
+
<div class="unified-head"><div><h2>AI Engineering</h2><p>Review your inputs, then generate a verified concept.</p></div><span id="engineer-stage-badge">WAITING FOR INPUTS</span></div>
|
|
22
|
+
<div class="unified-status-grid"><div><small>Model</small><b id="engineer-model-state">Connect above</b></div><div><small>Equipment</small><b id="engineer-equipment-state">0 supplied</b></div><div><small>Engine state</small><b id="engineer-validation-state">NOT RUN</b></div></div>
|
|
23
|
+
<div class="fields"><label for="ai-request">Ask the engineering agent (optional)</label><textarea id="ai-request" style="min-height:78px;font-family:inherit" maxlength="6000" placeholder="Example: Create an HMI for one floor, with conveyors CV101 and CV102. Do not invent tags or connections."></textarea></div>
|
|
24
|
+
<div class="unified-actions"><button type="button" id="engineer-run" class="primary">Analyze & verify</button></div>
|
|
25
|
+
<div id="engineer-results" class="unified-results hidden" role="status" aria-live="polite"></div>
|
|
26
|
+
<div id="engineer-approval" class="unified-approval hidden"><p id="engineer-review-summary"></p><label class="unified-affirm"><input type="checkbox" id="engineer-confirm"> I reviewed this concept · lab preview only.</label><button type="button" class="primary" id="engineer-build" disabled>Generate reviewed HMI →</button></div>
|
|
27
|
+
</section>
|
|
28
|
+
<section class="copilot-bar" aria-label="Engineering agent harness">
|
|
29
|
+
<div class="copilot-heading"><span class="copilot-icon" aria-hidden="true">✧</span><div><div class="eyebrow">ENGINEERING COPILOT / VALIDATED PROPOSALS</div><strong>Your data → AI proposals → independent engineering checks.</strong><p>After entering customer inputs, ask the connected model to propose up to 2 candidates. Deterministic tests reject unsafe or unsupported changes. Review before generating; Gateway FAT is separate.</p></div></div>
|
|
30
|
+
<div class="copilot-actions"><button type="button" id="harness-review">Review my data</button><button type="button" class="primary" id="harness-optimize">✧ Propose & static-check with AI</button><button type="button" id="harness-configure">Change model ⚙</button></div>
|
|
31
|
+
<div id="harness-results" class="copilot-results hidden" role="status" aria-live="polite"></div>
|
|
32
|
+
<div id="harness-approval" class="copilot-approval hidden"><span>Draft only. No PLC tags or Ignition FAT were verified.</span><button id="harness-apply" type="button">Review & apply to Creator →</button></div>
|
|
33
|
+
</section>
|
|
34
|
+
<div class="workspace-heading"><div><div class="eyebrow">YOUR WORKSPACE</div><h3>Create HMI</h3></div><span class="workspace-progress">SETUP <b>01 / 04</b></span></div><div class="steps" aria-label="HMI creation steps"><button class="step active" data-step="0">01 Project</button><button class="step" data-step="1">02 Equipment & flow</button><button class="step" data-step="2">03 OPC UA mappings</button><button class="step" data-step="3">04 Review & build</button></div>
|
|
35
|
+
<div id="step-0" class="panel active-panel"><div class="eyebrow">STEP 01 · FACILITY BRIEF</div><h2 style="margin-top:9px">Project details</h2><div class="fields grid"><div><label for="name">Project name *</label><input id="name" maxlength="90" placeholder="e.g. Distribution Center A"></div><div><label for="industry">Industry (optional)</label><input id="industry" maxlength="90" placeholder="Warehouse, Packaging, Water treatment…"></div></div><div class="fields"><label for="layout">HMI design</label><select id="layout"><option value="" selected>Choose an HMI design…</option><option value="spatial_overview">Spatial overview — large 3D viewer + inspector</option><option value="standard_2d_flow">Standard 2D — Facility Flow Overview (industrial operations)</option><option value="process_flow">Process flow — connected equipment</option><option value="machine_detail">Machine detail — equipment-focused view</option><option value="multi_zone">Multi-zone overview — facility navigation</option></select></div><div class="design-choice-cards" aria-label="Quick HMI style selection"><button type="button" data-design-choice="spatial_overview" class="design-choice"><span class="design-thumb design-thumb-3d" aria-hidden="true">◇ ◇ ◇</span><strong>3D Spatial · Flow</strong><small>Facility / equipment perspective</small></button><button type="button" data-design-choice="standard_2d_flow" class="design-choice"><span class="design-thumb design-thumb-2d" aria-hidden="true">▰ ━ ▰ ━ ▰</span><strong>Standard 2D · Flow</strong><small>Operator material-flow overview</small></button></div><div class="fields"><label for="palette">Customer color palette (design/layout unchanged)</label><select id="palette" aria-label="Customer color palette"><option value="" selected>Choose a customer palette…</option><option value="r9_cyan">R9 Navy / Cyan — Approved reference</option><option value="steel_blue">Graphite / Blue</option><option value="teal">Deep Teal / Mint</option><option value="warm_amber">Graphite / Amber</option></select></div><div class="fields"><label for="description">Plant description</label><textarea id="description" style="font-family:inherit;min-height:110px" maxlength="4000" placeholder="What does the plant do? What should the operator see?"></textarea></div><section class="project-package" id="project-package" aria-label="Import complete customer project ZIP">
|
|
36
|
+
<div class="eyebrow">START WITH FILES</div><h3>Import project ZIP</h3>
|
|
37
|
+
<p>Upload one package of equipment, connections, tags and requirements. Choose which project to use.</p>
|
|
38
|
+
<input type="file" accept=".zip,application/zip" id="project-package-file" aria-label="Import project ZIP">
|
|
39
|
+
<div id="project-package-result" class="package-result" role="status" aria-live="polite">No package selected</div>
|
|
40
|
+
<div id="project-package-review" hidden><label for="project-package-choice">Choose project</label><select id="project-package-choice"></select>
|
|
41
|
+
<button type="button" id="project-package-apply">Use selected inputs →</button></div>
|
|
42
|
+
<small>Input-only import · Never imports generated HMI or FAT reports as verified plant data.</small>
|
|
43
|
+
</section><section class="customer-documents" aria-label="Upload customer plant documents" id="customer-documents">
|
|
44
|
+
<div class="eyebrow">OPTIONAL FILES</div>
|
|
45
|
+
<h3>Plant documents</h3>
|
|
46
|
+
|
|
47
|
+
<label for="customer-source-files">Upload files (8 max)</label>
|
|
48
|
+
<input type="file" id="customer-source-files" multiple accept=".csv,.tsv,.xlsx,.docx,.pdf,.txt,.json,.png,.jpg,.jpeg,.webp,.dxf,.dwg">
|
|
49
|
+
|
|
50
|
+
<div id="customer-source-status" role="status" aria-live="polite">No files selected</div>
|
|
51
|
+
<div id="customer-source-list" class="customer-source-list"></div>
|
|
52
|
+
<details><summary>Extracted text</summary><pre id="customer-source-preview" class="customer-source-preview">No extracted text</pre></details>
|
|
53
|
+
<div class="customer-doc-actions">
|
|
54
|
+
<button type="button" id="customer-doc-structured" disabled>Import tables</button>
|
|
55
|
+
<button type="button" id="customer-doc-ai" disabled>Analyze documents</button>
|
|
56
|
+
</div>
|
|
57
|
+
<label class="customer-consent"><input type="checkbox" id="customer-doc-consent"> Allow AI to read extracted text (no secrets)</label>
|
|
58
|
+
<div id="customer-doc-draft" class="customer-doc-draft hidden" role="status" aria-live="polite"></div>
|
|
59
|
+
<button type="button" id="customer-doc-apply" hidden>Apply reviewed draft to empty Creator fields</button>
|
|
60
|
+
<small class="customer-source-note">Mappings remain unverified until source review.</small>
|
|
61
|
+
</section>
|
|
62
|
+
</div>
|
|
63
|
+
<div id="step-1" class="panel"><div class="eyebrow">STEP 02 · EQUIPMENT & FLOW</div><h2 style="margin-top:9px">Equipment & flow</h2><label for="equipment_csv">Equipment list — CSV (optional if mapped tags include asset IDs)</label><small class="tip">Minimum column: id. Optional name,kind,floor,zone,x,y,z (meters). Kind: conveyor, spiral, sorter, motor, vfd, photoeye, scanner, tank, pump, valve, robot, junction, room, other. Leave positions blank for conceptual auto-layout.</small><div class="file-row"><input aria-label="Import equipment CSV" type="file" accept=".csv,text/csv" data-load="equipment_csv"></div><textarea id="equipment_csv" spellcheck="false" placeholder="id,name,kind,floor,zone,x,y,z CV101,Conveyor 101,conveyor,1,RECEIVING,0,0,0"></textarea>
|
|
64
|
+
<div class="fields"><label for="connections_csv">Connections — CSV</label><small class="tip">from,to, one directed connection per row. Connections must refer to equipment IDs listed above.</small><div class="file-row"><input aria-label="Import connections CSV" type="file" accept=".csv,text/csv" data-load="connections_csv"></div><textarea id="connections_csv" spellcheck="false" style="min-height:105px" placeholder="from,to CV101,CV102"></textarea></div></div>
|
|
65
|
+
<div id="step-2" class="panel"><div class="eyebrow">STEP 03 · PLC DATA</div><h2 style="margin-top:9px">PLC signals</h2><label for="signals_csv">OPC UA signals — CSV</label><small class="tip">id,asset_id,role,datatype,namespace_uri,node_id,unit,polarity. Boolean run_feedback, fault, and photoeye_blocked require active_high/active_low. Analog roles require units.</small><div class="file-row"><input aria-label="Import signal CSV" type="file" accept=".csv,text/csv" data-load="signals_csv"></div><textarea id="signals_csv" style="min-height:240px" spellcheck="false" placeholder="id,asset_id,role,datatype,namespace_uri,node_id,unit,polarity S_CV101_RUN,CV101,run_feedback,Boolean,urn:plc:line1,Machine/CV101/RunFeedback,,active_high"></textarea>
|
|
66
|
+
<div class="notice">Every imported source remains PROPOSED until independently verified. No PLC writes. For a first demo, use the guided training NodeIds; for customer projects, import only actual source exports.</div></div>
|
|
67
|
+
<div id="step-3" class="panel"><div class="eyebrow">STEP 04 · REVIEW & GENERATE</div><h2 style="margin-top:9px">Review & generate</h2><label for="requirements">Customer requirements (one per line)</label><textarea id="requirements" style="min-height:130px;font-family:inherit" placeholder="Each conveyor must show run feedback and fault state. All scanner NO_READ events must be attributable to the correct scanner."></textarea>
|
|
68
|
+
<div class="upload-metadata"><b>Preview only.</b> UNKNOWN / NOT MAPPED until sourced. Gateway FAT is separate; PLC mappings and Ignition FAT remain unverified.</div>
|
|
69
|
+
<div class="ai-required-review"><span>✧ <b>AI + Engineering Review</b> — after entering your inputs, run the connected AI and deterministic harness before generating.</span><button type="button" id="start-ai-review">Analyze & improve with AI ↗</button></div><div class="actions"><button id="validate" class="primary">VALIDATE PROJECT DATA</button><button id="build" class="primary" disabled title="First connect AI and run engineering review">GENERATE HMI PREVIEW →</button></div><div class="status" id="result" role="status" aria-live="polite">No validation has run yet.</div><div id="success" class="success hidden"><strong>HMI ready for review</strong><div class="actions" style="margin:10px 0 0"><a id="preview-link" href="#" target="_blank" rel="noopener">Open full screen ↗</a><a id="studio-test-link" href="#" target="_blank" rel="noopener" style="background:#1c6881;color:#fff;border:1px solid #4a9cb5;padding:10px 13px;border-radius:5px;text-decoration:none">Test in Studio ↗</a></div><div style="margin-top:12px"><button type="button" id="v078-command-run" class="primary hidden" style="margin-right:8px">TEST START / STOP / RESET · VIRTUAL PLC</button><div id="v078-command-status" class="status hidden" role="status" aria-live="polite"></div><button type="button" id="v076-opc-run" class="primary hidden">RUN ISOLATED FAKE OPC UA FAT ↗</button><div id="v076-opc-status" role="status" aria-live="polite" class="status hidden"></div></div></div></div>
|
|
70
|
+
<section id="design-review" class="design-review hidden" aria-label="Live HMI design review">
|
|
71
|
+
<div class="design-review-head"><div><div class="eyebrow">DESIGN REVIEW</div><h3>Refine the full HMI</h3></div><span class="review-lab">PREVIEW ONLY</span></div>
|
|
72
|
+
<p class="review-intro">Describe a visual change. Preview, undo or export notes.</p>
|
|
73
|
+
<div id="review-chat-log" class="review-chat-log" aria-live="polite"><div class="review-msg assistant">Try “larger text”, “bigger map”, “wider inspector” or “compact KPI”.</div></div>
|
|
74
|
+
<form id="review-chat-form" class="review-chat-form"><label class="sr-only" for="review-chat-input">Design change</label><input id="review-chat-input" autocomplete="off" maxlength="220" placeholder="e.g. Make the map larger" aria-label="Design change" required><button type="submit" class="primary">Preview ↗</button></form>
|
|
75
|
+
<div class="review-tools"><button id="review-undo" type="button" disabled>Undo</button><button id="review-reset" type="button">Reset</button><button id="review-export" type="button">Export review notes</button></div>
|
|
76
|
+
<small class="review-disclaimer">Preview only; not saved into the generated project. PLC mappings, commands and safety logic are untouched.</small>
|
|
77
|
+
</section>
|
|
78
|
+
<div class="actions"><div class="action-left"><button id="prev">← Previous</button></div><div class="action-right"><span id="step-label" class="compact">Step 1 of 4</span><button class="primary" id="next">Next →</button></div></div>
|
|
79
|
+
<details class="info-drawer"><summary><span class="drawer-icon">i</span><span><strong>What information do I need?</strong><small>See a checklist of the typical plant documents.</small></span><b aria-hidden="true">⌄</b></summary><section class="onboard" aria-labelledby="inputs-heading"><div class="eyebrow">WHAT MOST CUSTOMERS ALREADY HAVE</div><h3 id="inputs-heading">Use the documents you already have</h3><p>Start with what is available. Do not invent missing PLC tags, photoeye associations or motor speed conversions.</p><div class="source-cards">
|
|
80
|
+
<div class="source-card"><b>① Equipment list / asset register</b><span>Conveyor IDs, motor names, sensors and machine types. From Excel, drawings, PLC I/O list.</span><em>RECOMMENDED FOR PREVIEW</em></div>
|
|
81
|
+
<div class="source-card"><b>② Layout / process flow</b><span>Simple sequence such as CV101 → CV102, floor plan or P&ID. Coordinates can be left blank for concept layout.</span><em>OPTIONAL FOR PREVIEW</em></div>
|
|
82
|
+
<div class="source-card"><b>③ PLC / OPC UA tag export</b><span>Approved Namespace URI, NodeId, units, polarity, signal associations and source documentation.</span><em>REQUIRED FOR VERIFIED MAPPING</em></div>
|
|
83
|
+
<div class="source-card"><b>④ Operating requirements</b><span>What operators need to see, alarms, diagnostics, navigation and customer FAT acceptance criteria.</span><em>REQUIRED FOR CUSTOMER ACCEPTANCE</em></div>
|
|
84
|
+
</div></section>
|
|
85
|
+
</details>
|
|
86
|
+
<details class="info-drawer ai-drawer"><summary><span class="drawer-icon spark">✧</span><span><strong>Advanced AI proposal details</strong><small>Inspect and apply a draft after connecting your model.</small></span><b aria-hidden="true">⌄</b></summary><section id="ai-assist" class="agent-panel" aria-label="AI engineering assistant">
|
|
87
|
+
<div class="agent-top"><div><div class="eyebrow">DEVAGENT / ENGINEERING AGENT / CUSTOMER MODEL</div><strong>AI-assisted engineering • your model, our validation</strong></div><button id="ai-toggle" type="button" aria-expanded="true">Manage AI connection ⚙</button></div>
|
|
88
|
+
<div id="ai-settings" class="hidden agent-settings">
|
|
89
|
+
<div class="connection-fields">
|
|
90
|
+
<div><label for="ai-provider">AI Provider</label><select id="ai-provider"><option value="openai">OpenAI</option><option value="anthropic">Anthropic Claude</option><option value="gemini">Google Gemini</option><option value="ollama">Ollama (DGX local)</option><option value="vllm">vLLM (DGX local, port 8000)</option><option value="openai_compatible">Custom OpenAI-compatible (admin allowlist)</option></select></div>
|
|
91
|
+
<div><label for="ai-model">Model ID</label><input id="ai-model" placeholder="Enter your model ID" autocomplete="off" maxlength="120" aria-describedby="model-id-tip"><small id="model-id-tip" class="model-id-tip">Exact name of your available model.</small></div>
|
|
92
|
+
<div id="ai-key-field"><label for="ai-key">API key <span class="field-optional">(cloud only)</span></label><input id="ai-key" type="password" maxlength="2048" autocomplete="off" placeholder="Paste your API key"></div>
|
|
93
|
+
</div>
|
|
94
|
+
<details class="connection-advanced"><summary>Advanced settings · Custom endpoint</summary><div class="connection-advanced-fields"><label for="ai-endpoint">Endpoint URL (leave blank for standard provider)</label><input id="ai-endpoint" maxlength="512" placeholder="Optional; provider defaults are used" autocomplete="off"><p class="compact">Ollama uses the permitted local endpoint. Custom provider hosts require an administrator allowlist.</p></div></details>
|
|
95
|
+
<div class="connection-actions"><button id="ai-test" type="button">Test Connection →</button><span id="ai-connection-status" role="status" aria-live="polite" class="compact">Not connected · Choose your provider and model.</span><button id="ai-continue" type="button" hidden>Continue to Creator ↓</button></div>
|
|
96
|
+
<p class="compact connection-privacy">🔒 The API key is not saved to browser storage. Project inputs go to your chosen AI provider only when you request AI analysis. Connection testing is not an engineering or production approval.</p>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<div class="agent-top"><button id="ai-draft" type="button" class="primary">Analyze & Propose Draft</button><span class="compact">AI drafts only • Engineer reviews • PLC writes disabled</span></div>
|
|
100
|
+
<div id="ai-result" class="status hidden" aria-live="polite"></div>
|
|
101
|
+
<div id="ai-approval" class="hidden"><p>Draft only. Review all proposed fields in Steps 1–4 before Build. No live signals are verified.</p><button id="ai-apply" type="button" class="primary">Apply Reviewed Draft to 4 Steps</button></div>
|
|
102
|
+
</section>
|
|
103
|
+
</details>
|
|
104
|
+
</section>
|
|
105
|
+
<aside class="aside"><section class="panel preview-shell" aria-label="Live equipment layout concept"><div class="preview-header"><div><div class="eyebrow" id="stage-eyebrow">INTERACTIVE WORKSPACE / LAYOUT CONCEPT</div><h2 id="stage-heading">Facility preview <span>✦</span></h2></div><span class="preview-mode" id="stage-mode">SCHEMATIC</span></div><div class="preview-stage" id="preview-stage"><div class="stage-watermark"><span class="watermark-dot"></span> CONCEPT VIEW · NOT AS BUILT</div><div class="preview-empty" id="stage-empty"><span class="cube">◇</span><strong>Your factory starts here</strong><p>Load a source-backed demo or add your own equipment to see your layout.</p></div><div class="stage-actions"><button type="button" id="stage-iso" aria-label="Isometric layout">ISO</button><button type="button" id="stage-top" aria-label="Top down layout">TOP</button><button type="button" id="stage-side" aria-label="Side layout">SIDE</button></div></div><section id="original-v8-panel" class="original-v8-panel hidden" aria-label="Original V8 Distribution Operations HMI"><div class="original-v8-toolbar"><div><b>Original V8 · Distribution Operations</b><span>SOURCE-PINNED · SYNTHETIC · NO PLC</span></div><div><a href="/original-v8/simulator.html" target="_blank" rel="noopener">Scenario controls ↗</a><a href="/original-v8/index.html" target="_blank" rel="noopener">Full screen ↗</a></div></div><iframe id="original-v8-frame" title="Original V8 Distribution Operations synthetic HMI" loading="lazy"></iframe></section><section id="original-r9-panel" class="original-r9-panel hidden" aria-label="Original R9 Four Spirals 3D concept HMI"><div class="original-r9-toolbar"><div><b>R9 Four Spirals · Source Snapshot</b><span>3 FLOORS · 4 SPIRALS · ISOLATED SYNTHETIC · NOT NATIVE IGNITION</span></div><div class="r9-preview-actions"><button type="button" id="r9-back-to-creator">← Creator</button><a href="/original-r9/index.html" target="_blank" rel="noopener">Full screen ↗</a></div></div><iframe id="original-r9-frame" title="Original R9 three-floor Four Spirals virtual HMI" loading="lazy"></iframe></section><section id="live-hmi-panel" class="live-hmi-panel hidden" aria-label="HMI preview"><div class="live-hmi-top"><b>Complete HMI screen</b><div class="hmi-inline-actions"><span>GENERATED CONCEPT · NOT PLC LIVE</span><button type="button" id="open-full-hmi-review">Expand HMI ↗</button></div></div><iframe id="live-hmi-frame" title="Generated HMI concept preview" loading="lazy"></iframe></section><div class="stage-footer"><div class="stage-row"><strong id="stage-title">Waiting for equipment</strong><small id="stage-count">0 assets · 0 links</small></div><div class="stage-details" id="stage-details">Select equipment to inspect the concept.</div><p class="stage-error" id="stage-error" role="status"></p></div><div class="stage-legend">Concept layout · Equipment color only · No live PLC data.</div></section>
|
|
106
|
+
<div class="panel"><div class="eyebrow">PROJECT SNAPSHOT</div><h2 style="margin-top:9px">Ready to design</h2><div class="readiness"><div class="readiness-item"><b id="ready-equipment">0</b><span>Equipment</span></div><div class="readiness-item"><b id="ready-signal">0</b><span>Signals</span></div><div class="readiness-item warn"><b id="ready-check">HOLD</b><span>Production gate</span></div></div><p class="trust-note" id="ready-message">Customer data · Engineering review required.</p></div>
|
|
107
|
+
<details class="panel compact-assurance"><summary>Engineering details <span>⌄</span></summary><div class="assurance-body"><div class="eyebrow">ENGINEERING ASSURANCE</div><h2 style="margin-top:9px">Technical checks</h2><div class="row"><span>Design system</span><b>Spatial Operations V1</b></div><div class="row"><span>Design palette</span><b id="side-palette">R9 Navy / Cyan</b></div><div class="row"><span>Customer layout</span><b id="side-layout">Spatial Overview</b></div><div class="row"><span>Equipment assets</span><b id="side-assets">—</b></div><div class="row"><span>Signal mappings</span><b id="side-signals">—</b></div><div class="row"><span>PLC write capability</span><b>DISABLED</b></div><div class="row"><span>OPC UA verification</span><b style="color:var(--warm)">PENDING</b></div><div class="row"><span>Native Ignition candidate</span><b style="color:var(--warm)">OFFLINE CLI</b></div><div class="row"><span>AI model connector</span><b>BYOM — SESSION ONLY</b></div><p class="compact">Production remains HOLD until live Gateway and site verification.</p></div></details></aside>
|
|
108
|
+
</div>
|
|
109
|
+
<section id="full-hmi-review" class="full-hmi-review hidden" role="dialog" aria-modal="true" aria-labelledby="full-review-title" tabindex="-1">
|
|
110
|
+
<header class="full-review-header">
|
|
111
|
+
<div><div class="full-review-overline">DEVAGENT / DESIGN REVIEW</div><h2 id="full-review-title">Complete HMI / SCADA Preview</h2></div>
|
|
112
|
+
<div class="full-review-header-actions"><span class="full-review-lab">CONCEPTUAL · NOT A LIVE PLC</span><a id="full-review-new-tab" href="#" target="_blank" rel="noopener">Open HMI tab ↗</a><button type="button" id="full-review-close" aria-label="Close full HMI review">Back to Creator ✕</button></div>
|
|
113
|
+
</header>
|
|
114
|
+
<div class="full-review-main"><div id="full-hmi-viewer-slot" class="full-hmi-viewer-slot" aria-label="Entire generated HMI"></div><aside id="full-hmi-editor-slot" class="full-hmi-editor-slot" aria-label="Live design review chat"></aside></div>
|
|
115
|
+
</section>
|
|
116
|
+
<script>
|
|
117
|
+
(()=>{'use strict';const $=id=>document.getElementById(id);let step=0;const names=['name','industry','layout','palette','description','equipment_csv','connections_csv','signals_csv','requirements'];function countLines(id){return Math.max(0,$(id).value.split(/\r?\n/).filter((x,i)=>i>0&&x.trim()).length)}function update(){document.querySelectorAll('.step').forEach((n,i)=>n.classList.toggle('active',i===step));for(let i=0;i<4;i++)$('step-'+i).classList.toggle('active-panel',i===step);$('step-label').textContent=`Step ${step+1} of 4`;document.querySelector('.workspace-progress b').textContent=`0${step+1} / 04`;$('prev').disabled=step===0;$('next').disabled=step===3;$('side-layout').textContent=$('layout').selectedOptions[0].textContent.split(' — ')[0];$('side-palette').textContent=$('palette').selectedOptions[0].textContent.split(' — ')[0];$('side-assets').textContent=countLines('equipment_csv');$('side-signals').textContent=countLines('signals_csv');document.dispatchEvent(new Event('devagent:changed'));}
|
|
118
|
+
const fields=()=>Object.fromEntries(names.map(n=>[n,$(n).value]));function go(n){step=Math.max(0,Math.min(3,n));update();}document.querySelectorAll('.step').forEach((n,i)=>n.addEventListener('click',()=>go(i)));$('next').addEventListener('click',()=>go(step+1));$('prev').addEventListener('click',()=>go(step-1));for(const n of names)$(n).addEventListener('input',update);$('layout').addEventListener('change',update);for(const btn of document.querySelectorAll('[data-design-choice]'))btn.addEventListener('click',()=>{$('layout').value=btn.dataset.designChoice;$('layout').dispatchEvent(new Event('input',{bubbles:true}));});document.addEventListener('devagent:changed',()=>document.querySelectorAll('[data-design-choice]').forEach(b=>b.classList.toggle('selected',b.dataset.designChoice===$('layout').value)));$('palette').addEventListener('change',update);
|
|
119
|
+
for(const input of document.querySelectorAll('[data-load]'))input.addEventListener('change',async()=>{const f=input.files?.[0];if(!f)return;if(f.size>100000){alert('CSV must be 100 KB or smaller');return;}const target=input.dataset.load;$(target).value=await f.text();update();});
|
|
120
|
+
async function call(endpoint){$('result').className='status';$('result').textContent='Checking engineering contract…';$('success').classList.add('hidden');for(const id of ['validate','build'])$(id).disabled=true;try{const response=await fetch(endpoint,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(fields())});const val=await response.json();if(!response.ok){$('result').textContent=`HOLD (${response.status})\n`+JSON.stringify(val,null,2);$('result').classList.add('hold');return;}if(endpoint==='/api/build'){$('result').textContent=`${val.status}\nProject: ${val.project_id}\nFAT cases generated: ${val.fat_cases}\nRenderer: ${val.renderer}\nWarnings: ${val.warnings?.length||0}`;$('success').classList.remove('hidden');$('preview-link').href=val.url;$('studio-test-link').href='/projects/'+val.project_id+'/test/index.html';}else{$('result').textContent=`${val.status}\nAssets: ${val.equipment_count}\nSignals: ${val.signals_proposed}\n`+val.issues.map(i=>`${i.severity} ${i.code}: ${i.message}`).join('\n');}$('result').classList.add(val.status==='HOLD'?'hold':'pass');}catch(err){$('result').textContent='HOLD: '+err.message;$('result').classList.add('hold');}finally{$('validate').disabled=false;$('build').disabled=!window.DevAgentHarness?.canBuild();}}
|
|
121
|
+
$('validate').addEventListener('click',()=>{if(!window.DevAgentAIFlow?.requireConnection())return;call('/api/validate')});$('build').addEventListener('click',()=>{
|
|
122
|
+
if(!window.DevAgentAIFlow?.requireConnection())return;
|
|
123
|
+
if(!window.DevAgentHarness?.canBuild()){ $('result').className='status hold';$('result').textContent='HOLD: First run AI + engineering review, inspect/apply a validated proposal, and do not modify the inputs after review.';return; }
|
|
124
|
+
call('/api/build');
|
|
125
|
+
});update();})();
|
|
126
|
+
</script><script type="module" src="/assets/creator_ui.mjs"></script><script type="module" src="/assets/creator_original_v8.mjs"></script><script type="module" src="/assets/creator_original_r9.mjs"></script><script src="/assets/live_design_review.js" defer></script><script src="/assets/agent.js" defer></script><script src="/assets/unified_engineer.js" defer></script><script src="/assets/v076_fat_ui.js" defer></script><script src="/assets/v078_command_ui.js" defer></script><script src="/assets/customer_documents.js" defer></script><script src="/assets/project_package.js" defer></script><script>
|
|
127
|
+
// Show a fail-closed, visible error if a future packaging/routing regression
|
|
128
|
+
// prevents the unified AI handler from loading. No model or API key is read.
|
|
129
|
+
document.addEventListener('DOMContentLoaded',()=>{
|
|
130
|
+
if(window.DevAgentUnifiedReady)return;
|
|
131
|
+
const state=document.getElementById('engineer-validation-state');
|
|
132
|
+
const msg=document.getElementById('engineer-results');
|
|
133
|
+
const badge=document.getElementById('engineer-stage-badge');
|
|
134
|
+
if(state)state.textContent='HOLD — AI UI UNAVAILABLE';
|
|
135
|
+
if(badge)badge.textContent='HOLD';
|
|
136
|
+
if(msg){msg.classList.remove('hidden');msg.classList.add('hold');
|
|
137
|
+
msg.textContent='AI Engineering failed to initialize. Reload the Creator. If this continues, the local /assets/unified_engineer.js script or its dependencies are unavailable.';}
|
|
138
|
+
});
|
|
139
|
+
</script></body></html>
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
:root{color-scheme:dark;--bg:#07131f;--navy:#0b1e2f;--panel:#0e2638;--panel2:#112b3e;--edge:#294b61;--cyan:#58c1dc;--muted:#82a6b9;--ink:#ecf5ff;--good:#24b79f;--warn:#e6bd70}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--ink);font-family:Inter,system-ui,-apple-system,'Segoe UI',sans-serif;font-size:13px}button,select{font:inherit}button{cursor:pointer}button:focus-visible,select:focus-visible,.stage:focus-visible{outline:2px solid var(--cyan);outline-offset:2px}button:disabled{cursor:not-allowed;opacity:.48}h1,h2,p{margin:0}.top{min-height:66px;display:flex;align-items:center;justify-content:space-between;padding:10px 18px;border-bottom:1px solid #1b3a4e;gap:12px;background:#071622}.top h1{font-size:19px;letter-spacing:.01em;margin-top:5px}.top-right{display:flex;align-items:flex-end;gap:10px;flex-direction:column;font-size:10px;letter-spacing:.06em;color:var(--cyan)}.eyebrow{font-size:10px;letter-spacing:.12em;color:var(--cyan);font-weight:700}.tag{border:1px solid var(--edge);border-radius:6px;padding:5px 8px;color:#87d0e1;font-size:10px;white-space:nowrap}.tag.warn{color:var(--warn);border-color:#796547}main{padding:12px 14px;max-width:2200px;margin:auto}.metrics{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:6px}.metric{min-height:84px;min-width:0;padding:10px 12px;border:1px solid var(--edge);border-radius:6px;background:var(--panel)}.metric small{font-weight:700;color:var(--cyan);font-size:10px}.metric strong{display:block;font-size:20px;margin:6px 0 2px;overflow-wrap:anywhere}.metric span{font-size:10px;color:var(--muted)}.command{margin:6px 0;min-height:55px;padding:8px 12px;border:1px solid var(--edge);border-radius:6px;background:var(--panel);display:flex;align-items:center;justify-content:space-between;gap:12px}.command b{display:block;font-size:13px}.command span{font-size:11px;color:var(--muted)}.command-buttons{display:flex;gap:6px;align-items:center}.muted-btn{background:#287e83;border:1px solid #519c9c;color:#fff;padding:10px 22px;border-radius:4px}.workspace{display:grid;grid-template-columns:minmax(0,1fr) 274px;gap:7px}.viewer-panel,.inspector,.contracts{border:1px solid var(--edge);border-radius:7px;background:var(--navy);min-width:0;overflow:hidden}.panel-head{min-height:81px;display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid #214256;gap:12px}.panel-head h2,.contract-heading h2{font-size:16px;margin:6px 0}.panel-head p,.contract-heading p{color:var(--muted);font-size:10px;margin-top:4px}.viewer-toolbar{display:flex;align-items:center;justify-content:space-between;min-height:44px;padding:6px 12px;border-bottom:1px solid var(--edge);gap:8px}.seg{display:flex;gap:4px;align-items:center;flex-wrap:wrap}.seg button{background:transparent;border:1px solid transparent;border-radius:3px;color:var(--muted);font-size:10px;padding:8px 10px}.seg button.active,.seg button:hover{background:#18536c;color:#d2faff;border-color:#317e98}.seg label{color:var(--cyan);font-size:10px}.seg select{background:#112c40;color:var(--ink);border:1px solid #386079;padding:6px;border-radius:4px}.stage{position:relative;min-height:510px;height:min(62vw,680px);background:radial-gradient(ellipse at 44% 35%,#133349 0%,#081826 72%);overflow:hidden;user-select:none}#scene-layer,#scene-layer canvas,#scene-layer svg{position:absolute;inset:0;width:100%;height:100%;display:block}.stage-caption{position:absolute;top:16px;left:16px;pointer-events:none;display:grid;gap:7px}.stage-caption strong{font-size:15px}.stage-caption small{font-size:10px;color:var(--muted)}.engine-tag{position:absolute;right:12px;top:14px;color:#78d7df;border:1px solid #27627a;padding:5px;border-radius:4px;font-size:10px;pointer-events:none}.stage-help{position:absolute;left:16px;bottom:14px;font-size:10px;line-height:1.6;color:#9ab6c5;pointer-events:none}.inspector-head{min-height:81px}.inspector-body{padding:14px;max-height:730px;overflow:auto}.inspector-body h2{font-size:22px;margin:7px 0}.inspector-body p{font-size:11px;color:#c2d5e2;line-height:1.5}.detail-grid{margin:15px 0;border-top:1px solid var(--edge)}.detail-row{display:flex;justify-content:space-between;gap:8px;border-bottom:1px solid #25465a;padding:12px 0;font-size:10px}.detail-row label{color:var(--muted)}.detail-row strong{text-align:right}.small-title{font-weight:700;font-size:10px;color:var(--cyan);letter-spacing:.1em;margin:16px 0}.signal-line{border-bottom:1px solid #203d4f;padding:9px 0;font-size:11px;overflow-wrap:anywhere}.signal-line small{display:block;color:var(--muted);margin-top:4px}.note{margin-top:15px;border:1px solid #2a586c;padding:12px;color:var(--muted);font-size:11px;line-height:1.6;background:#102b3b}.contracts{margin-top:8px}.contract-heading{display:flex;justify-content:space-between;padding:15px;align-items:center;gap:10px}.table-scroll{overflow-x:auto;max-height:285px;overflow-y:auto}table{border-collapse:collapse;width:100%;font-size:11px;min-width:790px}th{text-align:left;color:var(--cyan);font-size:10px;letter-spacing:.06em;background:#142f43}td,th{padding:10px 12px;border-top:1px solid #25485c}td{overflow-wrap:anywhere}td:nth-child(4){font-family:monospace;color:#9fc7da}.warning-text{color:var(--warn)}footer{padding:18px 2px 6px;color:var(--muted);font-size:10px;letter-spacing:.04em}@media(max-width:960px){.metrics{grid-template-columns:repeat(3,minmax(0,1fr))}.workspace{grid-template-columns:minmax(0,1fr)}.inspector-body{max-height:none}.stage{height:540px}.top-right{display:none}}@media(max-width:600px){.metrics{grid-template-columns:repeat(2,minmax(0,1fr))}.stage{height:430px;min-height:430px}.panel-head{flex-wrap:wrap}.command{flex-wrap:wrap}.command-buttons{flex-wrap:wrap}.metric strong{font-size:16px}.top h1{font-size:16px}}
|
|
2
|
+
|
|
3
|
+
/* Fixed signature style, responsive layout archetypes. */
|
|
4
|
+
.layout-process_flow .workspace{grid-template-columns:minmax(0,1fr) 310px}.layout-process_flow .stage{background:radial-gradient(ellipse at 40% 30%,#12364a 0%,#081826 76%)}.layout-machine_detail .workspace{grid-template-columns:minmax(0,1fr) 335px}.layout-machine_detail .inspector-body{max-height:780px}.layout-multi_zone .metrics{grid-template-columns:repeat(5,minmax(0,1fr))}@media(max-width:960px){.layout-process_flow .workspace,.layout-machine_detail .workspace{grid-template-columns:1fr}.layout-multi_zone .metrics{grid-template-columns:repeat(3,minmax(0,1fr))}}@media(max-width:600px){.layout-multi_zone .metrics{grid-template-columns:repeat(2,minmax(0,1fr))}}
|
|
5
|
+
|
|
6
|
+
/* V0.4.1: operator-first visual parity. Technical contracts are available only on request. */
|
|
7
|
+
.top-right{flex-direction:row;align-items:center;flex-wrap:wrap;justify-content:flex-end}
|
|
8
|
+
.engineering-link{border:1px solid #35677c;color:#a8d9e7;background:#103147;border-radius:4px;padding:8px 10px;font-size:10px;font-weight:700;letter-spacing:.065em}
|
|
9
|
+
.engineering-link:hover{background:#185270;color:white}
|
|
10
|
+
.stage{height:clamp(570px,70vh,950px);min-height:570px;background:radial-gradient(ellipse at 52% 60%,#12384c 0%,#081a2a 72%)}
|
|
11
|
+
.stage-caption{top:18px;left:18px}.stage-help{font-size:9px;opacity:.8}
|
|
12
|
+
.viewer-toolbar{background:#0b2233}.panel-head{background:#0b2435}
|
|
13
|
+
.engineering-dialog{max-width:min(1080px,94vw);width:100%;max-height:86vh;overflow-y:auto;color:var(--ink);background:#0a1d2d;border:1px solid #376077;border-radius:8px;padding:0;box-shadow:0 24px 90px #000d}
|
|
14
|
+
.engineering-dialog::backdrop{background:rgba(2,10,19,.83)}
|
|
15
|
+
.engineering-bar{padding:20px;display:flex;align-items:flex-start;justify-content:space-between;gap:12px;border-bottom:1px solid var(--edge)}
|
|
16
|
+
.engineering-bar h2{margin:6px 0;font-size:19px}.engineering-bar p{color:var(--muted);font-size:11px}
|
|
17
|
+
.engineering-close{color:var(--ink);background:#163a4e;border:1px solid #39708b;padding:9px 15px;border-radius:5px}
|
|
18
|
+
.engineering-dialog .contracts{margin:12px;border-radius:5px}
|
|
19
|
+
.engineering-dialog .table-scroll{max-height:52vh}
|
|
20
|
+
@media(max-width:960px){.stage{height:clamp(500px,65vh,800px);min-height:500px}.top-right{display:flex}.engineering-link{padding:7px}}
|
|
21
|
+
@media(max-width:600px){.stage{height:470px;min-height:470px}.top-right{gap:5px}.top-right strong{display:none}.engineering-dialog{max-width:96vw}}
|
|
22
|
+
|
|
23
|
+
/* DEVAGENT V0.4.3 DESIGN LOCK: brand palette changes only visual tokens. Layout is invariant. */
|
|
24
|
+
body[data-palette="r9_cyan"]{--bg:#07131f;--navy:#0b1e2f;--panel:#0e2638;--panel2:#112b3e;--edge:#294b61;--cyan:#58c1dc;--muted:#82a6b9;--stage-inner:#12384c;--stage-outer:#081a2a;--control-active:#18536c;--control-edge:#317e98;--accent-muted:#87d0e1}
|
|
25
|
+
body[data-palette="steel_blue"]{--bg:#0a121e;--navy:#0d1b2b;--panel:#152638;--panel2:#182f49;--edge:#365573;--cyan:#85c6ff;--muted:#9fb7cb;--stage-inner:#193750;--stage-outer:#081522;--control-active:#224d7a;--control-edge:#4079a6;--accent-muted:#b4dfff}
|
|
26
|
+
body[data-palette="teal"]{--bg:#07191d;--navy:#092328;--panel:#102c31;--panel2:#163a3d;--edge:#35656a;--cyan:#75dfce;--muted:#9abcc0;--stage-inner:#164448;--stage-outer:#061a22;--control-active:#1a6467;--control-edge:#36958d;--accent-muted:#9debdc}
|
|
27
|
+
body[data-palette="warm_amber"]{--bg:#17150f;--navy:#201d17;--panel:#2b261b;--panel2:#373020;--edge:#675c45;--cyan:#f5c77b;--muted:#b8aa90;--stage-inner:#333a3e;--stage-outer:#151b23;--control-active:#75602d;--control-edge:#aa8235;--accent-muted:#ffe2aa}
|
|
28
|
+
/* All palettes preserve the same professional hierarchy, spacing, typography and controls. */
|
|
29
|
+
body{background:var(--bg)}.top{background:var(--bg);border-bottom-color:var(--edge)}.panel-head,.viewer-toolbar{background:var(--panel)}
|
|
30
|
+
.stage,.layout-process_flow .stage{background:radial-gradient(ellipse at 52% 60%,var(--stage-inner) 0%,var(--stage-outer) 72%)}
|
|
31
|
+
.seg button.active,.seg button:hover{background:var(--control-active);border-color:var(--control-edge);color:var(--ink)}
|
|
32
|
+
.tag:not(.warn){color:var(--accent-muted)}.engineering-link{background:var(--panel2);border-color:var(--edge);color:var(--cyan)}.engineering-link:hover{background:var(--control-active)}
|
|
33
|
+
.seg select,.engineering-close{background:var(--panel2);border-color:var(--edge)}
|
|
34
|
+
.detail-row,.signal-line{border-color:var(--edge)}.note{background:var(--panel);border-color:var(--edge)}
|
|
35
|
+
/* A selection highlight is not a verified machine-state indication. */
|
|
36
|
+
/* Safety/unknown badges use immutable semantics, never the branding palette. */
|
|
37
|
+
|
|
38
|
+
/* R9 floor index is part of the operator UI, not technical mapping clutter. */
|
|
39
|
+
.layer-index{position:absolute;z-index:5;left:14px;top:95px;min-width:158px;padding:10px;border:1px solid var(--edge);background:rgba(8,28,42,.87);border-radius:6px;box-shadow:0 6px 24px #0006}
|
|
40
|
+
.layer-index[hidden]{display:none!important}
|
|
41
|
+
.layer-index .eyebrow{margin-bottom:9px}
|
|
42
|
+
#layer-buttons{display:grid;gap:5px}.layer-option{display:flex;align-items:center;gap:10px;width:100%;text-align:left;background:rgba(18,53,74,.7);border:1px solid var(--edge);border-radius:4px;color:var(--ink);padding:8px}
|
|
43
|
+
.layer-option:hover,.layer-option:focus-visible{outline:1px solid var(--cyan);background:var(--control-active)}
|
|
44
|
+
.layer-option strong{font-size:14px;color:var(--cyan);min-width:24px}.layer-option small{font-size:10px;color:var(--muted)}
|
|
45
|
+
@media(max-width:700px){.layer-index{left:8px;top:80px;min-width:130px;padding:6px}.layer-option{padding:5px}.layer-option small{font-size:9px}}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
/* DEVAGENT V0.5.5 R9 VISUAL DEPTH LOCK -- operator view only.
|
|
49
|
+
Read-only controls stay truly disabled; identity colors are not machine states. */
|
|
50
|
+
.stage,.layout-process_flow .stage{
|
|
51
|
+
background:
|
|
52
|
+
radial-gradient(ellipse 68% 65% at 54% 48%,rgba(32,91,120,.66) 0%,rgba(16,53,76,.33) 43%,transparent 77%),
|
|
53
|
+
radial-gradient(ellipse 65% 48% at 69% 71%,rgba(37,137,150,.13),transparent 78%),
|
|
54
|
+
linear-gradient(161deg,#0b2639 0%,#0a1e30 46%,#061420 100%);
|
|
55
|
+
isolation:isolate;
|
|
56
|
+
}
|
|
57
|
+
.stage::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:0;
|
|
58
|
+
background:linear-gradient(100deg,rgba(86,186,211,.035),transparent 48%,rgba(0,0,0,.10));}
|
|
59
|
+
#scene-layer{z-index:1} .stage-caption,.stage-help,.engine-tag{z-index:3}
|
|
60
|
+
.stage-caption{filter:drop-shadow(0 2px 7px #03111cb3)}
|
|
61
|
+
.stage-help{padding:4px 6px;background:rgba(4,17,29,.72);border:1px solid rgba(57,124,150,.26);border-radius:3px;max-width:calc(100% - 32px)}
|
|
62
|
+
.layer-index{z-index:4;box-shadow:0 12px 40px #0009;border-color:rgba(81,171,193,.32)}
|
|
63
|
+
.metric{background:linear-gradient(165deg,var(--panel2),var(--panel));border-color:var(--edge)}
|
|
64
|
+
.metric strong{color:#f3f9ff;text-shadow:0 1px 10px rgba(93,184,211,.13)}
|
|
65
|
+
.viewer-panel,.inspector{box-shadow:0 14px 45px rgba(0,0,0,.16)}
|
|
66
|
+
.viewer-toolbar{background:linear-gradient(180deg,var(--panel),var(--navy))}
|
|
67
|
+
.command-buttons .muted-btn{font-weight:800;font-size:11px;min-width:88px;letter-spacing:.04em;
|
|
68
|
+
border-radius:4px;box-shadow:inset 0 1px rgba(255,255,255,.14);opacity:.75;
|
|
69
|
+
cursor:not-allowed;filter:saturate(.75);}
|
|
70
|
+
.command-buttons .cmd-start{background:#087f69;border-color:#25ab92;color:#eafff8}
|
|
71
|
+
.command-buttons .cmd-stop{background:#a52e48;border-color:#d96074;color:#fff5f6}
|
|
72
|
+
.command-buttons .cmd-reset{background:#236e9c;border-color:#4c9bca;color:#f1faff}
|
|
73
|
+
.command-buttons .muted-btn:disabled{opacity:.75}
|
|
74
|
+
.command .tag.warn{background:rgba(85,49,19,.15);color:#e6bd70;font-weight:700}
|
|
75
|
+
/* Decorative brand/accent styling never overrides fault, warning, or read-only semantics. */
|
|
76
|
+
@media(max-width:600px){.command-buttons .muted-btn{min-width:70px;padding:9px 13px}}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
/* DevAgent V0.5.6 source-qualified operations command layer; never masquerades as live OPC */
|
|
80
|
+
.ops-board{margin-top:7px;margin-bottom:8px;border:1px solid var(--edge);background:linear-gradient(145deg,var(--panel),var(--navy));border-radius:6px;overflow:hidden}
|
|
81
|
+
.ops-heading{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:12px 14px 9px}
|
|
82
|
+
.ops-heading b{font-size:15px;color:#f1f9fd;display:block;margin-top:4px}.ops-mode{font-size:10px;letter-spacing:.04em;color:#f0c276;background:#3c2d1c;border:1px solid #775a38;border-radius:3px;padding:7px 9px;font-weight:700}
|
|
83
|
+
.ops-metrics{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:6px;padding:0 8px 9px}
|
|
84
|
+
.ops-metric{min-height:82px;padding:10px 11px;border:1px solid var(--edge);background:rgba(10,33,51,.88);border-radius:5px;display:flex;flex-direction:column;gap:5px}
|
|
85
|
+
.ops-metric small{color:#86c9d8;font-size:9px;font-weight:800;letter-spacing:.052em}.ops-metric strong{font-size:23px;color:#f3faff;font-variant-numeric:tabular-nums}.ops-metric span{font-size:10px;color:#9abbcd}
|
|
86
|
+
.ops-metric.critical{border-color:#b44459;background:linear-gradient(155deg,#3b1e2b,#132638)}.ops-metric.critical strong{color:#ffb4bb}
|
|
87
|
+
.alerts-dialog{width:min(760px,96vw);max-height:86vh;overflow:auto;background:#091c2b;border:1px solid #47677a;border-radius:7px;color:#eff7fb;box-shadow:0 28px 100px #000c;padding:0}.alerts-dialog::backdrop{background:#000b}
|
|
88
|
+
.alerts-title{padding:18px 20px;display:flex;justify-content:space-between;gap:14px;border-bottom:1px solid var(--edge)}.alerts-title h2{font-size:18px;margin:8px 0}.alerts-title p{font-size:11px;color:#b2cdd8}.alerts-title button{background:#164154;color:#def5fc;border:1px solid #3e7086;padding:8px 12px;align-self:start;border-radius:4px}
|
|
89
|
+
.alerts-summary{display:flex;justify-content:space-between;align-items:center;padding:12px 20px;border-bottom:1px solid var(--edge);gap:12px;color:#e8ca8b;font-size:12px}.alerts-summary span{color:#a3c1cd;font-size:10px}
|
|
90
|
+
.alerts-items{padding:13px 18px;max-height:52vh;overflow:auto;display:grid;gap:7px}.alert-item{background:#102b3d;border:1px solid #355669;border-left:4px solid #a6b8c3;border-radius:4px;padding:11px 13px;display:grid;gap:6px}.alert-item.critical{border-left-color:#ef6c82}.alert-item.warning{border-left-color:#e9bf63}.alert-item.info{border-left-color:#69c3bd}.alert-item .event-header{display:flex;align-items:center;justify-content:space-between;gap:8px}.alert-item b{font-size:12px}.alert-item p{font-size:11px;margin:0;color:#c7d9e4}.alert-item small{color:#83a5b4;font-size:10px}.alert-item button{border:1px solid #43677b;background:#173a4d;padding:6px;color:#dceaf1;font-size:10px;border-radius:3px}.empty-alerts{color:#adbdc9;font-size:12px}.alerts-disclaimer{margin:10px 18px 18px;font-size:10px;color:#bc9c70;line-height:1.6}
|
|
91
|
+
.ops-review{margin:15px;border:1px solid #385c70;background:#102c3f;padding:17px;border-radius:5px}.ops-review h2{font-size:16px;margin:7px 0}.ops-review p{font-size:11px;color:#b9d0dc;line-height:1.7}.lab-tools{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin:10px 0}.lab-tools button,.file-label{background:#1b5369;border:1px solid #3c859b;color:white;padding:8px 10px;font-size:10px;font-weight:700;border-radius:4px;cursor:pointer}.lab-tools button:disabled{opacity:.4;cursor:not-allowed}.lab-tools input{max-width:230px;font-size:10px}#ops-import-status,#ops-contract-summary{color:#9cbece;font-size:11px;margin:10px 0}
|
|
92
|
+
@media(max-width:1180px){.ops-metrics{grid-template-columns:repeat(3,minmax(0,1fr))}}@media(max-width:620px){.ops-metrics{grid-template-columns:repeat(2,minmax(0,1fr))}.ops-heading{flex-wrap:wrap}.alert-bell{padding:6px}}
|
|
93
|
+
|
|
94
|
+
.ops-metric:has(#kpi-scanresult) strong,.ops-metric:has(#kpi-barcode) strong{font-size:17px;overflow-wrap:anywhere}
|
|
95
|
+
|
|
96
|
+
/* V0.5.7-r2: compact operator notification affordance, no full-width ribbon. */
|
|
97
|
+
.top-right .alert-bell{position:relative;display:inline-flex;align-items:center;justify-content:center;flex:none;
|
|
98
|
+
width:35px;height:35px;padding:0;margin:0 3px;border-radius:6px;cursor:pointer;
|
|
99
|
+
border:1px solid #456276;color:#cfe8f1;background:linear-gradient(155deg,#153549,#0a2435);
|
|
100
|
+
transition:border-color .12s,background .12s;}
|
|
101
|
+
.alert-bell .bell-icon{display:block;width:19px;height:19px;fill:none;stroke:currentColor;
|
|
102
|
+
stroke-width:1.8;stroke-linejoin:round;stroke-linecap:round;}
|
|
103
|
+
.alert-bell:hover,.alert-bell:focus-visible{border-color:#75bad0;background:#20475a;outline-offset:2px}
|
|
104
|
+
.alert-bell .bell-badge{position:absolute;right:-6px;top:-6px;display:inline-grid;place-items:center;
|
|
105
|
+
min-width:17px;height:17px;padding:0 3px;border-radius:999px;box-sizing:border-box;
|
|
106
|
+
font-size:10px;font-weight:800;line-height:1;border:1px solid #0c2434;color:#fff;
|
|
107
|
+
background:#8c9dad;box-shadow:0 2px 8px #0009;}
|
|
108
|
+
.alert-bell .bell-badge[hidden]{display:none!important}
|
|
109
|
+
.alert-bell.is-unknown{border-color:#71603e;color:#e2c17e}
|
|
110
|
+
.alert-bell .bell-badge.is-unknown,.alert-bell .bell-badge.has-warning{background:#aa7b2b;color:#fff4d6}
|
|
111
|
+
.alert-bell.has-alarm{border-color:#bc455b;color:#ffb5bf}
|
|
112
|
+
.alert-bell .bell-badge.has-alarm{background:#c53958;color:white}
|
|
113
|
+
.alert-bell.has-warning{border-color:#b58d44;color:#e5c17c}
|
|
114
|
+
@media(max-width:620px){.top-right .alert-bell{width:32px;height:32px}}
|
|
115
|
+
|
|
116
|
+
/* V0.6: replay and FAT tools never appear in operator or engineering HMI. */
|
|
117
|
+
.ops-review[hidden]{display:none!important}
|
|
118
|
+
|
|
119
|
+
/* V0.6.1 clean operator shell. Studio & FAT live exclusively in separate workspace. */
|
|
120
|
+
.ops-metric[hidden]{display:none!important}
|
|
121
|
+
.ops-metrics{grid-template-columns:repeat(auto-fit,minmax(175px,1fr));gap:7px}
|
|
122
|
+
.ops-metric{min-height:74px}
|
|
123
|
+
.ops-heading{padding:9px 14px}
|
|
124
|
+
.ops-heading .eyebrow{display:none}
|
|
125
|
+
.stage{min-height:520px}
|
|
126
|
+
.engine-tag{opacity:.7}
|
|
127
|
+
.top-right{gap:10px}
|
|
128
|
+
@media(max-width:780px){.ops-metrics{grid-template-columns:repeat(2,minmax(0,1fr))}.stage{min-height:440px}}
|
|
129
|
+
@media(max-width:480px){.ops-metrics{grid-template-columns:repeat(2,minmax(0,1fr))}}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
/* V0.6.2: R9 operator controls. These are standard HMI affordances,
|
|
133
|
+
intentionally disabled until a separately verified command authority exists.
|
|
134
|
+
No simulation/FAT actions or write APIs are exposed on the operator UI. */
|
|
135
|
+
.operator-command-bar{
|
|
136
|
+
margin:0 0 8px;padding:8px 12px;min-height:58px;
|
|
137
|
+
border:1px solid var(--edge);border-radius:6px;
|
|
138
|
+
background:linear-gradient(160deg,#102e41,#0b2031);
|
|
139
|
+
display:flex;align-items:center;justify-content:space-between;gap:12px;
|
|
140
|
+
}
|
|
141
|
+
.operator-command-identity{display:flex;flex-direction:column;gap:3px;min-width:130px}
|
|
142
|
+
.operator-command-identity strong{font-size:12px;color:#ecf5ff}
|
|
143
|
+
.operator-command-identity span{font-size:10px;color:var(--muted)}
|
|
144
|
+
.operator-command-actions{display:flex;align-items:center;justify-content:center;gap:7px;flex-wrap:wrap;margin-left:auto}
|
|
145
|
+
.operator-command-button{
|
|
146
|
+
min-width:92px;min-height:37px;padding:8px 13px;
|
|
147
|
+
border:1px solid transparent;border-radius:4px;color:white;
|
|
148
|
+
font-size:11px;font-weight:800;letter-spacing:.045em;
|
|
149
|
+
box-shadow:inset 0 1px rgba(255,255,255,.12);
|
|
150
|
+
}
|
|
151
|
+
.operator-command-button.cmd-start{background:#0b806e;border-color:#2cae93;color:#eefdf8}
|
|
152
|
+
.operator-command-button.cmd-stop{background:#ab334c;border-color:#d36275;color:#fff3f5}
|
|
153
|
+
.operator-command-button.cmd-reset{background:#266e9c;border-color:#4b9ac4;color:#f0f8ff}
|
|
154
|
+
.operator-command-button.cmd-ack{background:#96702c;border-color:#c49b4b;color:#fff7e5}
|
|
155
|
+
.operator-command-button:disabled{
|
|
156
|
+
cursor:not-allowed;opacity:.72;filter:saturate(.72);
|
|
157
|
+
box-shadow:inset 0 1px rgba(255,255,255,.12);
|
|
158
|
+
}
|
|
159
|
+
.operator-control-lock{
|
|
160
|
+
flex:none;border:1px solid #7e6342;color:#f0ca88;
|
|
161
|
+
background:#292718;border-radius:4px;padding:8px 9px;
|
|
162
|
+
font-size:10px;font-weight:800;white-space:nowrap;letter-spacing:.035em;
|
|
163
|
+
}
|
|
164
|
+
@media(max-width:1000px){
|
|
165
|
+
.operator-command-bar{flex-wrap:wrap;justify-content:flex-start}
|
|
166
|
+
.operator-command-actions{margin-left:0;justify-content:flex-start}
|
|
167
|
+
.operator-control-lock{margin-left:auto}
|
|
168
|
+
}
|
|
169
|
+
@media(max-width:580px){
|
|
170
|
+
.operator-command-actions{width:100%;display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}
|
|
171
|
+
.operator-command-button{min-width:0;min-height:42px}
|
|
172
|
+
.operator-control-lock{margin-left:0}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* V0.6.4: operator equipment discovery without debug controls */
|
|
176
|
+
.equipment-jump-label{display:block;margin:0 0 6px;color:var(--cyan);font-size:10px;font-weight:700;letter-spacing:.09em}
|
|
177
|
+
.equipment-jump{width:100%;max-width:100%;padding:9px 8px;margin:0 0 14px;border-radius:5px;border:1px solid #3a6a7e;background:#0a2436;color:var(--ink);font-size:12px}
|
|
178
|
+
.equipment-jump:focus-visible{outline:2px solid var(--cyan)}
|
|
179
|
+
.mapping-disclaimer{color:var(--muted);font-size:10px;line-height:1.5;margin:5px 0 12px}
|
|
180
|
+
|
|
181
|
+
/* Synthetic command authority is NEVER PLC authority. */
|
|
182
|
+
.operator-control-lock.sim-linked{border-color:#287d82;color:#a5e6e2;background:#12333a}
|
|
183
|
+
|
|
184
|
+
/* V0.7.7.3 — focused diagnostic inspection. Never authorizes PLC commands. */
|
|
185
|
+
.detail-navigation{display:grid;grid-template-columns:1fr auto;gap:7px;margin-top:9px}
|
|
186
|
+
.detail-navigation button{border:1px solid #396b81;background:#194052;color:#e0f8ff;border-radius:5px;padding:10px 8px;font-weight:750;font-size:10px}
|
|
187
|
+
.control-readiness{font-size:10px;color:#a5c3d3;letter-spacing:.07em;font-weight:800;margin:8px 0}
|
|
188
|
+
.device-command-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:7px}
|
|
189
|
+
.device-command-intent{padding:11px 8px;border:1px solid #476477;background:#193344;color:#a8bfd0;border-radius:5px;font-size:11px;font-weight:800}
|
|
190
|
+
.device-command-intent:disabled{opacity:.72;cursor:not-allowed}
|
|
191
|
+
.control-lock-note{margin:10px 0 0;color:#cfae77!important;font-size:10px!important;line-height:1.65}
|