Commit Graph
7144 Commits
Author SHA1 Message Date
Mike-Solar 74b080f88a feat(oaktimeline): multicam enable/disable/switch commands, split copies the dependency graph
- oaktimeline::multicam: clip_find_multicam (buffer/tex_in depth-1
  lookup), multicam_enable/disable (rewire sequence<->clip through a
  MultiCamNode), multicam_switch (split-preserving-links at the
  playhead, each half owns an independent multicam copy, linked clips
  switched together) as single undo commands with C++ labels.
- BlockSplitCommand now duplicates the clip's whole dependency graph
  (copy_node_and_dependency_graph_minus_items) instead of just the
  block core, matching the C++ BlockSplitCommand::prepare semantics;
  undo detaches the copied subgraph, redo re-attaches identity-
  preserving.
- oaknode: fix serializer dropping edges from the first-created node
  (ptr=0 was not registered in id_map), restoring sequence_in edge
  round-trips; multicam node and clip wiring serializer round-trip
  tests.
2026-08-18 20:45:01 +08:00
Mike-Solar 431b9ed2b1 feat(oakrender): render-process isolation S1 - dispatcher, scheduler, real worker
Per the M15 design (docs/zh/plans/riir/M15-render-process-isolation.md):

- ipc.rs moved into oakrender with protocol v2: hello_caps,
  render_batch, batch_accepted, frame_failed; main-process-assigned
  slots; BGRA8 slot format. POSIX shm verified to 1GiB on macOS.
- ProcessDispatcher: spawns oak-worker processes, handshake, stdio
  NDJSON control, shm segment lifecycle with generation-tagged keys,
  crash detection with bounded restart and frame redispatch, zero-copy
  ShmFrameRef delivery and copy counters.
- PreviewScheduler: interleaved batch claiming (frame % W per worker,
  no work stealing), seek > playback-distance > background priority,
  credit-based flow control, crash recovery.
- oak-worker renders for real: graph snapshot deserialization, montage
  decode+composite straight into the assigned shm slot, F32->BGRA8
  final conversion in-worker, OFX plugin executor installed in-worker,
  crash hooks for isolation testing.

Thread pool coexists for now (S2 removes it). Integration tests cover
two-worker zero-copy rendering, crash isolation with redelivery, and
real H.264 footage decode into slots.
2026-08-18 18:58:38 +08:00
Mike-Solar f2af92958a feat(app): proxy editing and audio sync, aligned with the C++ version
Proxy: preview-path proxy substitution (global UseProxyMedia AND
per-footage enabled AND on-disk ready; export always uses originals),
proxy generate/delete/reveal/enable actions, ProxyDialog with global
and per-footage custom params, Tools menu + context-menu Proxy
submenus, progress in the status bar, OVE serialization of proxy
metadata and source_start_time.

Sync: timeline context-menu Synchronize by Source Time / by Waveform /
by Waveform (Adjust Speed) with ctrl-shift-w, cache-envelope
extraction with validity masks, reference/anchor selection and
single multi-undo application (replace-with-gap, speed adjust,
re-place) mirroring timelinewidget.cpp semantics.
2026-08-18 18:58:26 +08:00
Mike-Solar 2db1615453 feat(oakplugin): wire OpenFX plugins into the node graph and renderer
- oaknode: dynamic node factory registration, PluginNode value model
  pushing PluginJobPayload, traverser texture passthrough for texture
  inputs, type-stamped RefBox::get_checked.
- oakrender: PluginExecutor dependency-inversion slot; eval resolves
  and executes plugin jobs, purple frame on failure.
- oakplugin: node_factory with full OFX param -> node input
  translation (15 types, color semantics heuristic, combo ordering,
  secret/ui_group/ui_page, clip inputs), plugin instance registry,
  render executor + duplicator installation, progress reporter and
  active-viewer provider injection points, U8/U16/F16 input
  conversion with NaN scrubbing, in-place output frame writeback fix.
- gl_bridge.rs documents the wgpu<->GL interop spike: Metal-first on
  macOS rules out wgpu-hal GL interop; offscreen GL context deferred.

End-to-end tests cover registration, param translation, CPU render
pixel assertions, identity passthrough and NaN fallback.
2026-08-18 17:15:13 +08:00
Mike-Solar 9daa266189 feat(app): gpui action/keymap shortcut system, full main menu, context menus
Port the C++ menu/shortcut architecture (origin/main) to the Rust shell:

- src/actions.rs: action registry (123 entries with stable C++ ids,
  i18n keys, default key bindings, routing targets) driving both the
  menu bar and App::bind_keys; src/shortcuts.rs flat table removed.
- src/panels/commands.rs: PanelCommandHandler trait routing playback,
  editing, zoom, markers etc. to the currently focused panel.
- make_menus rebuilt from the registry: full File/Edit/View/Playback/
  Sequence/Window/Tools/Help trees aligned with the C++ main menu.
- src/menus/: shared context-menu infrastructure; right-click menus
  for timeline (clip/empty/track head/ruler), project explorer,
  viewers, node editor, inspector effect stack, with i18n EN/ZH.

Synchronize/Proxy/Multi-Cam entries exist but stay disabled pending
their engine wiring phases.
2026-08-18 17:15:00 +08:00
Mike-Solar 6576113a69 chore: bump gpui submodule (node zoom scaling, explorer thumbnails, divider drag fix) 2026-08-18 12:42:09 +08:00
Mike-Solar 33db5657e0 feat(app): reprobe legacy footage on load; background thumbnail pipeline
- graphops: reprobe_unprobed_footage resolves relative filenames against
  the project dir and probes footage whose stream metadata is missing
  (C++ saves and older Rust files), restoring durations and track kinds
- real: legacy footage is reprobed on open/adopt; a background worker
  renders first-frame thumbnails (hash-cached PNGs) and the project
  explorer data source attaches them as they complete
2026-08-18 12:42:03 +08:00
Mike-Solar b8a3beaee4 feat(probe): record and print the footage stream inventory
FootageBehavior now keeps the probed stream list (video/audio, per-stream
duration in rationals) instead of dropping it, and the probe CLI walks
that inventory to report real durations, frame rates and stream counts
rather than the previous zero placeholders.
2026-08-18 12:41:55 +08:00
Mike-Solar 61da70ecf8 fix(build): launch crash — @rpath/libz.1.dylib had no LC_RPATH
The static FFmpeg's external codec libs pull in -lz, which on this
toolchain resolves to a copy whose install name is @rpath/libz.1.dylib
(zlib-ng-compat); without an LC_RPATH entry all three binaries died in
dyld at startup. The app/cli/worker build scripts now emit
-Wl,-rpath,/usr/lib.

Also: FFMPEG_DIR moves into the committed .cargo/config.toml as a
workspace-relative [env] entry — ffmpeg-sys-next's build script cannot
read .env files, and without it the crate silently linked the shared
Homebrew FFmpeg while oakffmpeg-link emitted the static transitive
flags (mixed linkage). docs/build.md updated.
2026-08-17 19:42:45 +08:00
Mike-Solar b36cbd6b6f refactor: purge CHandle from module internals (M14 R5)
Module-internal object references are Rust types now (values, Arc,
Mutex); CHandle remains only at the oakengine C-ABI boundary:

- oakundo: the global stack holds UndoStack/UndoCommand values
  directly (stack token is the static's address)
- oaktimeline: marker/workarea boxes carry Arc<Mutex<T>>; commands
  share the same allocation through Arc clones (readers in oakengine
  stubs and the app's graphops updated to lock)
- oaktask/oakstorage: sessions, write-through bindings and the
  database backend pass ProjectArc; the Session drops its manual
  release bookkeeping; nodeutil keeps the CHandle<->Arc boundary
  conversion (release_project restored for the app)
- oakcodec: handle.rs deleted outright (no facade entry needed it);
  texture/block placeholders are unit structs
- oakrender: copier's project handle is an identity u64; alive-count
  machinery removed; handle.rs is make_owned/get/get_mut only
- oakplugin: the instance registry is gone (its unregister key never
  matched, leaking weak entries); handle.rs is the RefBox boundary type
- oaknode/oakcommon: only dead guard/borrow helpers removed; external
  payload handles (texture/processor) documented as the boundary

Flake hunts landed along the way: the audio recording test serializes
on the shared manager lock with a normalized state; the autocacher
cancel test uses a slow producer so cancellation is deterministic.
2026-08-17 16:40:15 +08:00
Mike-Solar ede03d0bfe chore: bump gpui submodule (track toggles + explorer icon buttons) 2026-08-17 01:37:46 +08:00
Mike-Solar 21cc2fba24 feat(app): track-header toggles, effect library, panel titles (design parity)
- track headers: name + visible/mute/lock toggles, undoable through
  graphops, honored by the montage (muted tracks are skipped) and by
  the edit guards (locked tracks reject trims/moves/deletes)
- project explorer gains a panel title row; the tree/icons toggle is
  now small icon buttons with tooltips
- new effect library dock panel (every addable effect; double-click
  appends to the selected clip's chain)
- screenshots refreshed (zh/en, window/manager/preferences)
2026-08-17 01:37:31 +08:00
Mike-Solar c5f1d0d76c refactor(engine): pure cdylib + undo-stack test race fix (M14 R4)
- oakengine is now cdylib-only (no rlib/staticlib consumers anywhere;
  cargo tree verified) — the plugin/external C ABI layer; README and
  docs updated
- cd.yml drops the dylib embedding/re-sign steps (the app no longer
  links it)
- test race root-caused and fixed for good: the global undo stack lock
  is now a re-entrant mutex (parking_lot) shared by every test that
  drives the stack, including the previously unlocked node/render
  families; the render-manager serial-ordering bug (an earlier repro
  test initialized the global manager before the not-initialized test)
  is fixed with a shared SERIAL guard and a manager shutdown
- 5 consecutive parallel runs clean; serial 209/209
2026-08-17 00:51:36 +08:00
Mike-Solar 022c0a7a5a refactor(app): cut liboakengine, link module rlibs directly (M14 R3)
- real.rs rewritten over module Rust APIs (Arc<Mutex<Project>> +
  NodeId; the addref handle dance and renderer boxes are gone);
  AppEngine trait and all panels untouched
- new app assembly layers: graphops (project/timeline/edit
  primitives), effectchain (chain composition with undo groups),
  renderops (montage build + ticket render + ExportTask export),
  library via oakstorage directly
- module-side safe API additions: oakundo global value-semantic
  push/undo/redo + from_closures, oakstorage project_arc_of
- deleted: src/oakui/ffi.rs, src/oakui/host_syms.rs, the dylib link
  config in build.rs (only the gpui IOSurface framework link remains)
- the binary carries zero liboakengine references (otool/nm verified);
  101 app tests green incl. the real-render and full-res e2e tests
- behavior improvements for free: sequences land in the project graph
  (the facade scratch-project deviation is gone), footage drops take
  one undo record, effect remove/reorder undo restores edges
2026-08-16 23:36:43 +08:00
Mike-Solar a45a7af2ac refactor(cli,worker): cut liboakengine, link module rlibs directly (M14 R2)
- oak-cli: new engine.rs assembly layer maps every facade call to
  module Rust APIs (oaknode graph/serializer, oaktimeline commands,
  oakrender ticket arena, oaktask ExportTask, oakcommon config); the
  ffi/optional/host layers and build.rs link config are gone
- oak-worker: the worker session + POSIX shm transport moved into the
  crate (oakrender backend + serde_json control plane); no dylib
- both binaries carry zero liboakengine references (otool verified);
  tests green (30 cli / 41 worker)
2026-08-16 21:16:27 +08:00
Mike-Solar 8a2e45225f refactor: sink facade glue into modules (M14 R1)
- oakundo::global: the process-global undo stack, grouping and a
  command observer API; facade undo.rs becomes a thin forwarder
- oakstorage::writethrough: the binding table, snapshot thread, flush
  and config resolution; it subscribes to oakundo's observer itself
- the remaining non-forwarding facade logic (TaskMeta, effect chains,
  timeline composites, RendererBox, exporter path) is documented as
  facade-owned with reasons
- facade exports unchanged; full suite stays green (the one
  render_manager_not_initialized failure is pre-existing on the base
  commit)
2026-08-16 20:37:45 +08:00
Mike-Solar f59c7c8476 docs(riir): M14 — frontends link module rlibs directly (plan A) 2026-08-16 19:54:48 +08:00
Mike-Solar 4f6c903edb chore: bump gpui submodule (dock panel drag-drop layout) 2026-08-16 19:46:34 +08:00
Mike-Solar b2d353fe99 fix(app): footage drop auto-creates the media's track
A fresh sequence has no tracks and a drop rejected with 'display track
does not exist'; wrong-kind drops also rejected. Dropping footage now
creates a matching track first (the Premiere convention), so the
drag-to-timeline path works on empty timelines too.
2026-08-16 19:46:05 +08:00
Mike-Solar 2958464bd7 chore: bump gpui submodule (explorer icons + footage drag) 2026-08-16 19:07:35 +08:00
Mike-Solar 061aab9180 fix(app): full-res worker crash + source playback frozen + cli/worker DS batch
- full-res source jobs carried only the footage node box: dropping the
  project mid-flight left the node dangling (crash in the worker's free
  path) and the node was also freed twice (at renderer creation AND at
  release). The request now carries an addref'd project copy and the
  node is freed exactly once; regression test drops the project before
  the worker runs
- the source clock ticked at the SEQUENCE length, so playing footage
  with an empty sequence froze the source playhead at 0; the source
  clock now loops at the selected footage's probed duration
- oak-cli/oak-worker: DeepSeek's refactor batch (clap migration, engine
  FFI consumers); the stale exporter-family test flipped to the real
  contract (mp4 is written)
- engine: render_audio smoke test on an empty sequence
2026-08-16 19:07:07 +08:00
Mike-Solar 36ca413a84 ci: restore macOS and move all runners back to WarpBuild
CI matrix: warp-ubuntu-latest-x64-8x / warp-macos-15-arm64-6x /
warp-windows-latest-x64-16x (the macOS steps were still in place, only
the matrix entry was missing). CD: macOS DMG job re-enabled on the warp
Apple Silicon runner; linux and release jobs back on warp-ubuntu;
Windows NSIS stays disabled until the engine links there.
2026-08-16 18:21:10 +08:00
Mike-Solar f3f3748173 ci(cd): release needs only the linux job while macos/windows stay disabled 2026-08-16 18:09:36 +08:00
Mike-Solar 8334894984 ci(cd): packaging verified end-to-end on macOS
- every job builds -p oakengine first (the dylib is a build-dep-only
  artifact otherwise and cli/worker link-search the profile dir)
- 512px icon (tauri-icns only maps 512@1x/1024@2x); dylib embedding
  derives the path from the binary's otool reference; fpm invoked from
  the gem bin dir; GITHUB_ENV blocks batched (SC2129); actionlint.yaml
  whitelists the warp runner labels
- Windows job disabled with a reference block until the engine links
  there
- real run: Oak-macOS-arm64.dmg produced, app launches from the volume
  (known gap recorded: the dmg still dynamically links Homebrew codec
  libs; not self-contained yet)
2026-08-16 18:05:03 +08:00
Mike-Solar 4e5d8747b5 refactor(oakengine): absorb oakcore host symbols into the dylib
The 'host-provided' oakcore_audioparams_* runtime imports dated from
the deleted C++ host; the facade is their only caller. The dylib now
defines and exports the six symbols itself (repr(C) AudioParams mirror,
liboakcore-compatible semantics), -Wl,-undefined,dynamic_lookup is gone,
and the Windows DLL undefined-symbol blocker is removed by construction
(Windows CI/packaging stays off until a real toolchain verifies links).
2026-08-16 18:05:03 +08:00
Mike-Solar e346ea5338 feat(app): P5 — async full-res render, full preferences, shortcut map
- viewers show the 480px proxy immediately and a background thread
  fills the sequence-resolution frame (per-monitor in-flight job,
  generation-based staleness, playback skips full-res)
- preferences dialog complete: cache dir (now consumed by
  default_disk_cache_path), proxy policy/divider, snapshot interval
  (write-through era autosave), default transition length, audio
  in/out devices (new facade device-enumeration exports; audio init
  from config — playback was never creating the audio instance),
  language/theme/renderer backend, all persisted via config
- shortcut map (src/shortcuts.rs): space/J/K/L, I/O, S split, A/^A,
  ⌘Z/⌘⇧Z, ⌘N/⌘O/⌘S/⌘E/⌘Q, frame step, Home, track zoom; dispatch
  shares the menu action path and stays silent over modals
- screenshots: preferences dialog zh/en captured and reviewed
2026-08-16 18:05:03 +08:00
Mike-Solar 466cdcb7d7 chore: bump gpui submodule (ruler markers + work-area drag) 2026-08-16 16:06:36 +08:00
Mike-Solar 92daff1a83 feat(engine,app): timeline markers, work area, cross-track move (M12 P4)
- facade: oakengine_sequence_set_workarea_undoable (enable+range as one
  undo record); marker add/remove/list already existed and are now
  covered by it_timeline (10 new tests: markers, workarea, cross-track)
- fixes: stubs workarea_get honored NULL out-params (is_enabled always
  failed); export tasks honor custom ranges (export_params_pod dropped
  them; oaktask EncodingParams carries has_custom_range)
- app: markers on the ruler (gpui diamond markers), menu
  sequence-add/remove marker, set/clear work area (selected-clip bounds
  or playhead+1), ruler drag previews live and commits one undoable
  record (C++ ruler semantics); export uses the work area when enabled
- cross-track clip moves were already wired; now covered end to end
2026-08-16 16:06:19 +08:00
Mike-Solar 23e6fa7a5b chore: bump gpui submodule (project explorer drop fix) 2026-08-16 15:05:36 +08:00
Mike-Solar 693e2df5eb feat(app): project browser on real project data + drag-drop import (M12 P3)
- ProjectDataSource<RealEngine> reads the real bin tree (roots/
  children via the facade folder/footage enumeration)
- AppEngine::import_footage implemented (facade project_import_footage,
  last_error surfaced); double-click opens in the source viewer
- dragging files onto the browser imports them (also fixes a real gpui
  bug: ExternalPaths arrives as the bare type, not Arc-wrapped, so
  drops never fired)
- tests: real-engine import->browser listing, widget drop routing,
  facade folder enumeration failure matrix
2026-08-16 15:05:01 +08:00
Mike-Solar 0f82092e95 refactor(app): retire manual-save semantics (M13 D5)
- AppEngine: save_project -> export_project_path(explicit path);
  project_modified removed (write-through has no dirty flag)
- File menu's save/save-as are the export path (extension-dispatched
  ove/otio/fcpxml); the library row export path is unchanged
- facade project_save/is_modified stay frozen, documented as the
  legacy export surface
- docs: M13 D5 checked off; M12 inventory updated
2026-08-16 14:17:45 +08:00
Mike-Solar 025dc88c25 feat(storage,app): PostgreSQL backend (D3) + project manager window (D4)
D3: oakdb+pg:// fully wired (shared sea-orm entities, BIGSERIAL DDL,
connect-probe instead of pool retry on dead servers); Storage/Backend=pg
+ Storage/PgUrl config; 13 OAK_TEST_PG_URL-gated PG tests (verified
against a Docker postgres:16), always-on clean-error tests otherwise.

D4: DaVinci-style project manager — list with derived stats, create/
rename/duplicate/delete (confirm)/import/export (native dialogs,
ove/otio/fcpxml), shown at startup and from the file menu; facade
oakengine_library_* exports (list/create/delete/rename/duplicate/
import/export + project_load_library that binds write-through);
save/save-as menu becomes 'export project file', open splits into
from-library/from-file; status bar shows library write state; storage
activates on app start and flushes on exit; spawn_modal reentrancy
fixed (window-callback path) with a doc note.

Also: the P1 audio test's environment probe was lost in the ffi purge;
restored on cpal (the output device is cpal now).
2026-08-16 10:39:31 +08:00
Mike-Solar 5fabad8efd feat(engine): write-through persistence (M13 D2)
- facade storage session manager: project handles bind to the default
  SQLite library on project_new/load; every undo push/group_end/jump
  write-throughs via DatabaseBackend::save (diff journal); project_free
  flushes and unbinds
- background snapshot thread (Storage/SnapshotIntervalSec, latest-wins,
  newest 3 kept) with exit flush (oakengine_storage_flush)
- config-gated: storage only activates with an explicit
  Storage/Backend=sqlite, so headless consumers and tests never touch
  the real library; new exports: storage_flush/is_bound/last_error
- it_storage: kill -9 recovery, cross-session undo, snapshot pruning,
  multi-project isolation, graceful degradation
- also fixes a real config test polluting the user config.ini and the
  undo-stack test races
2026-08-16 08:52:23 +08:00
Mike-Solar b35f3b49bc docs: project storage architecture (en+zh), linked from README and docs index 2026-08-16 01:40:53 +08:00
Mike-Solar 3dfeed67f5 feat(storage): database backend D1 — SQLite, node-granular journal, snapshots, persistent undo
- sea-orm schema: projects/settings/snapshots/journal (journal rows
  are per-node before/after images produced by diffing the serializer
  output, never full-project copies)
- replay = latest snapshot + journal; load_at() rewinds to any command
  seq (cross-session undo history); snapshot interval and journal
  retention configurable; snapshots pruned to the newest 3
- project manager API: list/delete/duplicate/rename, export/import
  (.ove/.otio/.fcpxml), stats derivation; PG surfaces as E_NO_BACKEND
  until D3
- docs(riir): M13 finalized (aggregate-granular persistence)
2026-08-16 01:38:27 +08:00
Mike-Solar 530bc762dc docs(riir): M13 final — node-granular journal (diff-produced), snapshots, persistent undo 2026-08-16 01:19:41 +08:00
Mike-Solar 78d8073c89 docs(riir): M13 — database backend, write-through persistence, project manager 2026-08-16 00:40:02 +08:00
Mike-Solar ab1a2e9c7b refactor: drop internal bridge/ffi layers; exporter family lands
Single-lib cleanup: the per-crate src/bridge/ and src/ffi.rs layers are
gone (oakundo/oakcommon/oaknode/oaktimeline/oakcodec/oakaudio/
oakrender/oaktask/oakplugin/oakstorage); cross-crate calls are plain
Rust, CHandle marshalling shrinks to the oakengine boundary, and tests
call the Rust APIs directly (pure C-ABI wrapper tests removed where
the domain layer already covers the behavior).

exporter.h family implemented: oakengine_export_render (CLI contract),
oakengine_export_render_with_params (was a stub), last_error and
progress callback; synchronous path reuses task_create_export +
start_sync. Fixes on the way: oaktask video ticket self-deadlock,
audio params dropped on the export path, codec encoder AAC slicing and
H.264 time base. Real-mp4 tests cover both entry points, progress and
the illegal-argument matrix.

Also: oakstorage session maps null project handles to None (version-
info path), configstore test double literal 3.14 -> 3.15 (clippy PI
lint), oakaudio output callback scratch buffer + env-aware P1 test,
cli media round-trip test uses a generated 16-frame clip (no more
minute-long debug runs).
2026-08-16 00:33:45 +08:00
Mike-Solar 2248be8567 feat(storage): real oakstorage file backends + full-timeline .ove serializer
oakstorage (new workspace member): URI dispatch, pluggable backends
(ove-xml built in, otio/fcpxml via oakotio, C-vtable foreign
registration), the M10 C API surface, version info codes, last-error
and alive accounting; round-trip tests per backend.

oaknode serializer: persists the full timeline — sequence track lists,
track block lists, block ranges/media_in/speed/flags, clip footage
references, footage filename+streams, folder children — through
<custom> behavior hooks with two-phase reference resolution; loads the
C++ <olive><project><layout> containers (golden: tests/
project_with_footage.ove); round-trip is field-by-field and
byte-idempotent.
2026-08-14 15:14:38 +08:00
Mike-Solar 48d3027d50 feat(engine,app): node editor bound to the facade graph (M12 P2)
facade (API only extended): oakengine_sequence_as_node /
_sequence_node_count / _sequence_node_at / _sequence_remove_node;
remove validates ownership by project UUID (arena slot/generation
collide across projects). it_node covers enumeration/edits and the
NULL/illegal matrix.

app: NodeGraphDataSource enumerates the current sequence's graph —
footage / effect / clip / output cards at their context positions
(deterministic role-grid fallback), real edges plus synthesized
clip->sequence tex_in edges; connect/disconnect/remove/drag-release
all go through undoable facade commands, drag previews stay local.
2026-08-14 13:33:49 +08:00
Mike-Solar 4240df1d71 refactor(crates): implement std::error::Error for all module error enums
thiserror derive across oakundo/oakcommon/oaknode/oaktimeline/oaktask/
oakotio/oakcodec/oakaudio/oakrender/oakplugin/oakengine/oakstorage;
Display carries the module prefix and the Failed context, source()
stays default except oakotio's #[from] forwarding. code() mappings and
variants unchanged; each error.rs gains Display/object-safety/code
regression tests.
2026-08-14 05:45:05 +08:00
Mike-Solar d460d57805 fix(oakaudio): P1 output hardening
- output callback reuses a scratch buffer instead of allocating per
  call (real-time rule)
- P1 consumption test probes real callback delivery and skips on
  headless/background sessions (CoreAudio starts the stream but never
  runs it outside the GUI session), with a 30s poll for slow HAL
  startup; restores the manager singleton state afterwards
- waveform: drop leftover DBG-WF debug prints
2026-08-14 05:45:05 +08:00
Mike-Solar c8c282f06c chore: bump gpui submodule (content-width dock tabs, rounded clips) 2026-08-13 23:39:42 +08:00
Mike-Solar f0517fe6af feat(app): UI walkthrough pass — faithful screenshots, dock labels, timeline clips, status bar, meter
- screenshot example inits i18n and captures both zh-CN and en-US
  (docs/screenshot-window{,-en}.png)
- dock tabs size to content (no more 64px truncation); viewer/panel
  titles follow the design (素材查看器·name etc.)
- mock project carries V1/V2 video + A1/A2 audio clips rendered as
  rounded green bars; timeline clip geometry/rounded corners match the
  design; status bar visible with full content; audio meter strip
  docked at the program viewer's right edge; project explorer rows
  have icons
- tests/waveform_e2e.rs: waveform cache extracts real peaks and hits
  cache on re-query (P4 acceptance)
2026-08-13 23:37:57 +08:00
Mike-Solar c5287ff234 chore: bump gpui submodule (menu scrubbing + density pass) 2026-08-13 18:16:27 +08:00
Mike-Solar 5afa95c80e feat(render,app): footage decode lands (M12 P0) + UI density pass
engine:
- oakrender eval footage hook decodes via oakcodec (JobSpec::Footage
  carries filename/stream); ticket/ffi/manager wiring, real-media
  decode test with programmatically generated MPEG-2
- oakrender bridge/codec.rs + node.rs: direct oakcodec/oaknode calls;
  the crate's dlsym module is gone (project_deep_copy/sync_copy remain
  documented always-fail stubs — never implemented in oaknode)
- oakaudio waveform/decoder path adjustments for the decode hook

app (gpui + gpui_widgets):
- menu bar scrubbing: hovering another top-level title while a menu is
  open switches to it; popup width is content-aware (CJK-aware) instead
  of fixed 160px
- density pass: window rem 16 -> 14px, menu rows 26 -> 22px, dock tabs
  32 -> 26px, viewer transport tightened
- open/import/save-as use the native platform file dialogs
  (prompt_for_paths / prompt_for_new_path; multi-select import);
  MockEngine records imported footage for tests
- project explorer Tree/Icons toggle is localized (explorer.tree /
  explorer.icons widget keys)
2026-08-13 18:16:10 +08:00
Mike-Solar 3625e37081 docs(riir): M12 app rewrite plan (gpui shell, P0-P5 phases) 2026-08-12 14:35:14 +08:00
Mike-Solar 06f47235b2 feat(engine,app): source-monitor frames + real audio meter
source monitor:
- new facade exports oakengine_renderer_create_for_node (render any
  node, not just sequences) and oakengine_project_footage_at (fetch a
  footage node by index); it_render covers the e2e render plus the
  NULL/illegal matrix
- RealEngine renders the selected footage's real frames to the source
  viewer (per-node renderer slot, frame cache invalidated on selection
  change, synthetic fallback kept)
- known gap (documented): pixels stay transparent black until
  oakrender's footage decode hook lands — the render surface itself is
  real end to end

audio meter:
- oakaudio manager can now report per-channel linear peaks of the
  buffered output (PreviewAudioDevice::peek_tail + levelmeter analysis
  of the newest 8192 frames, packed/planar F32)
- new facade export oakengine_audio_output_levels (negative codes pass
  through); RealEngine's AudioMeterDataSource reads it instead of
  returning hardcoded silence
- tests: module peak readback + facade validation/readback matrix
2026-08-12 14:19:18 +08:00
Mike-Solar f1f4124b18 chore: bump gpui submodule (tab-policy formatting pass) 2026-08-11 23:06:40 +08:00
Mike-Solar 18ff60f147 feat(engine): clip move, clip effect_input, mandatory static FFmpeg
- oakengine_sequence_move_clip implemented for real (oaktimeline
  TrackMoveBlockCommand; fixes the graph-ownership/gap-anchor/ripple
  trim bugs the stub was hiding); same-track via the frozen C ABI,
  cross-track supported by the module command
- oaknode clip blocks now declare a tex_in texture input and set
  effect_input to it, so timeline clips can host effect chains; facade
  test covers effect insert/remove on a real clip
- oakffmpeg-link: FFMPEG_DIR is now mandatory with a clear panic (a
  Homebrew upgrade left the system ffmpeg .pc pointing at a deleted
  dav1d Cellar path, breaking links); reads a git-ignored workspace
  .env for IDEs that cannot inject env vars (RustRover); links the C++
  stdlib for C++ codec libs (svt-av1)
- oakengine re-exports oaknode so tests share one crate instance;
  it_node uses the direct instance's value type where it calls the
  module FFI (the --workspace dev-dependency feature split builds
  oaknode twice)
2026-08-11 23:04:48 +08:00