Darkwood · Symfony · PHP FFI · Flow

When AI Becomes a Library

The Nolife Local Experiment
Depth Anything 3 + Symfony + PHP FFI + Darkwood Flow

@matyo91

The default reflex

We use LLMs for everything.

problem
↓
large model
↓
prompt
↓
text
02 | reflex @matyo91

The question

What if the task already has a specialized model?

problem
↓
specialized model
↓
structured computation
03 | question @matyo91

Depth is not language

General LLM

"The mountains are far away."

Depth Anything 3

504 × 280
depth values

relative units · not meters

Turbo colormap depth
04 | depth @matyo91

Depth Anything 3

RGB image
↓
Depth Anything 3
↓
depth
confidence
camera
3D / GLB

DA3-BASE · relative depth · not meters

05 | da3 @matyo91

Research → runtime

PyTorch checkpoint
↓
GGUF
↓
ggml
↓
Metal
↓
Depth · Camera · GLB
06 | runtime @matyo91

What “specialized” means

Not this project

fine-tuning
LoRA
training from scratch

This project

purpose-trained model
local native runtime
quantized representation
07 | specialized @matyo91

The unusual constraint

No Python service.
No cloud AI API.

Symfony
↓
PHP FFI
↓
native model
08 | php @matyo91

Architecture

Symfony hosts the boundary.

flowchart TB
  B["Browser"]
  S["Symfony"]
  F["Darkwood Flow"]
  N["NativeDepthBridge"]
  FFI["PHP FFI"]
  L["libdepthanything"]
  G["ggml / Metal"]
  D["Depth Anything 3"]
  B --> S --> F --> N --> FFI --> L --> G --> D
09 | architecture @matyo91

Ownership

PHP owns

HTTP · validation · Flow orchestration · GD colormap Twig · CLI · observability

Native owns

ViT · DPT · depth confidence · camera Metal · GLB export

PHP does not perform matrix multiplication.

10 | ownership @matyo91

PHP FFI

$ffi->da_capi_depth_dense(
    $ctx, $imagePath, …
);
native pointer
↓
PHP array
↓
da_capi_free_floats
11 | ffi @matyo91

Application pipeline

Upload
↓
Validate → Infer → Colormap
↓
GLB → Result
Upload UI

Darkwood Flow · explicit steps · per-step timings

12 | pipeline @matyo91

Observability

Flow did not make inference faster.
It made the pipeline visible.

Flow step timings
13 | flow @matyo91

The benchmark that did not make sense

Stepms
Validate~3
InferDepth~2639
Colormap~86
ExportScene~2535
Total~5260

Why is ExportScene another 2.5 seconds?

14 | anomaly @matyo91

Before

The hidden second inference

image
 ├── inference → depth
 └── inference → GLB

da_capi_depth_dense da_capi_export_glb → depth_pose_native() × 2

15 | double pass @matyo91

After

One inference, several outputs

image
  ↓
one inference
  ↓
native result
 ├── depth
 ├── confidence
 ├── camera
 └── GLB

da_capi_export_glb_cached · ABI v11

16 | fix @matyo91

Measured impact

~5.26 s 2 native inferences
~3.27 s 1 native inference · GLB ~19 ms
Original vs depth

504×336 · q4_k · warm · Apple M4 / Metal

17 | impact @matyo91

Measurement discipline

Different tensor size ≠ regression

SourceProcessedInfer median
1280×720504×280~2495 ms
1024×680504×336~3.0–3.2 s

Compare processed resolution — not headline numbers alone.

18 | resolution @matyo91

Quantization

4× smaller.
Not 4× faster.

q4_k ~99 MB · ~2495 ms
f32 ~393 MB · ~2495 ms

Warm infer-only · 504×280 · Apple M4 / Metal

19 | quant @matyo91

Local means local

No remote AI inference
No cloud API at runtime
GGUF on disk · Metal on device
Demo runtime works with networking disabled
GLB viewer
20 | local @matyo91

AI becomes infrastructure

The model starts to look like a dependency.

php bin/console app:depth-check
php bin/console app:depth-bench
php bin/console app:depth-stress
php bin/console app:depth-cleanup

Flow / PHP overhead ~114 ms · infer dominates

21 | infra @matyo91

Development loop

Early

idea
→ ask agent
→ inspect

Later

observe → evidence
→ issue → agent
→ implement → measure
22 | loop @matyo91

Issue-first

The valuable part was the problem definition.

Observation:
Two native inference passes.

Evidence:
Infer ≈ 2.6 s · GLB ≈ 2.5 s

Constraint:
One inference per request.

Expected:
Reuse native dense result.

Non-goal:
No Messenger / concurrency layer.
23 | issue @matyo91

Synthesis

Reduce unnecessary generality.

Runtime

general model
        ↓
specialized model

Development

general prompt
        ↓
well-defined issue
24 | synthesis @matyo91

What I learned

PHP FFI was enough
Native infer dominates cost
Observability found the real bug
q4_k saved size, not latency here
Context > code volume
Evidence beats speculation
25 | learned @matyo91

Conclusion

The task should determine the model, the architecture, and the prompt.

Depth Anything 3 · specialized computation
↓
Darkwood Flow · observable pipeline
↓
Issue-first brief · specialized context
26 | conclusion @matyo91

Resources

Source

github.com/matyo91/nolife-local

Slides

github.com/matyo91/slidewire

Upstream

github.com/mudler/depth-anything.cpp

@matyo91 · Darkwood @matyo91